Skip to main content

Full text of "The MDL Programming Environment"

See other formats


LABORATORY FOR 
COMPUTER SCIENCE 




MASSACHUSETTS 
INSTITUTE OF 
TECHNOLOGY 


7<£> 

.My/ 

,P?t> 

Z^ 


JAN 25 198$ 



no 


MIT/LCS/TR-294 


THE MDL 
PROGRAMMING 
ENVIRONMENT 


P. David Lebling 



545 TECHNOLOGY SQUARE. CAMBRIDGE, MASSACHUSETTS 02139 



77 Massachusetts Avenue 
Cambridge, MA 02139 
http://libraries.mit.edu/ask 


DISCLAIMER NOTICE 

Due to the condition of the original material, there are unavoidable 
flaws in this reproduction. We have made every effort possible to 
provide you with the best copy available. 

Thank you. 


MITLibraries 



The MDL Programming Environment 


P. David Lebling 


May, 1980 


Laboratory for Computer Science 
Massachusetts Institute of Technology 
Cambridge, Massachusetts 02139 



1 


The MDL Programming Knvironment 


Table of Contents 

1. Overview of the MDL Programming Environment 7 

2. The Package System 9 

2.1. r rhc Theory of Lexical Blocking in MDL 9 

2.2. Package System Overview 10 

2.2.1. Sample PACKAGE 11 

2.3. PACKAGE 11 

2.3.1. ENTRY 12 

2.3.2. USE 13 

2.3.3. USE-DATUM 13 

2.3.4. DROP and L-UNUSE 13 

2.3.5. HNOPACKAGE 13 

2.3.6. PACKAGE Restrictions 14 

2.3.7. ENTRY Name Conflicts 14 

3. Program Writing and Debugging Aids 15 

3.1. Pretty-Printing 15 

3.1.1. PPR I NT Control Switches 16 

3.1.2. Lower- level Pretty Printing 17 

3.1.3. Ampersand Printing 18 

3.1.4. Examining the Stack 18 

3.2. The MDL Editor 19 

3.2.1. The Edit ’LISTEN Loop’ 20 

3.2.1. 1. Ihc Reader 20 

3.2.1.2. 'Ihc Ampersand Printer 21 

3.2.2. Edit Commands 21 

3.2.2.1. General 21 

3.2.2.2. General Commands 22 

3.2.2.3. Movement Commands 23 

3.2.2.4. Printing Commands 24 

3.2.2.5. Editing Commands 25 

3.2.2.6. Macro Facility 27 

1121 . Cursors 28 

3.2.2.8. Breakpoints 29 

3.2.2.9. Edit Monitors 30 

3.2.2.10. User-defined Edit Commands 31 

3.2.3. Examples 31 

3.2.3. 1. Simple Editing 31 

3.2.3.2. X and G Commands 32 

3.2.3.3. Unconditional Breakpoints 33 

3.2.3.4. Conditional Breakpoints 34 

3.2.4. I idit Command Summary 36 

3.3. Debugging and the Interpreter 37 


Table of Contents 



ii 


'ITic MDL Programming Environment 


3.4. Loading and Dumping 39 

3.5. l hc One-step Debugger 41 

3.5.1. MDL Debugger Command Summary 43 

3.5.2. MDL Debugger Special Features 43 

3.6. Execution Tracing 44 

3.6.1. Using TRACE 44 

3.6.2. Understanding TRACE 45 

3.7. Monitors 46 

3.7.1. Monitor Internals 46 

3.7.2. Creating MONITORS 47 

3.7.3. Monitor Events 48 

3.7.4. Killing Monitors 49 

3.7.5. Other Monitor Routines 49 

3.7.6. What You Can't Do with Monitors 49 

3.8. FIND ATOM 50 

3.9. "PINFO" 52 

3.10. Debugging in a Run-time Environment 52 

3.10.1. DFL 52 

3.10.2. RDFL 53 

3.10.3. UN-DFL 53 

3.10.4. UNLINK 54 

3.11. CRITIC 55 

3.1 1.1. Global problems with the Group 56 

3.11.2. Parameter list problems 57 

3.11.3. Unused ATOMs 58 

3.11.4. Function calling errors 59 

3.11.5. SPEC1AL/UNSPEC1AL problems 59 

3.11.6. DHCLing problems 59 

3.11.7. Miscellaneous 61 

3.12. Program Environments • 61 

4. The Library System 63 

4.1. Program Libraries 63 

4.1.1. Library Searching 64 

4.1.2. Dynamic leading 65 

4.1.3. USK-DEFER 66 

4.1.4. USE-TOTAL 66 

4.1.5. Translations 66 

4.1.6. Hie Library Data Pile 67 

4.1.7. Run-time Switches 68 

4.1.8. Library Utility Functions 69 

4.1.9. Internal Library Functions 70 

4.1.10. Library Maintenance 71 

4.2. The Purc-inapping Library 72 

4.2.1. The Demon 73 


Table of Contents 



I'hc MOL. Programming Knvironmcnt 


iii 


4.2.2. User Programs 74 

4.2.2. 1. Listing Functions 74 

4.2.2.2. Find Functions • 75 

4.2.2.3. Other Functions 75 

4.2.3. Using DBMA1N 76 

4.2.4. Garbage Collection 76 

4.2.5. Internal Structure 77 

5. The Compiler 79 

5.1. Interfacing to the Compiler 79 

5.1.1. Compiler Functions 79 

5.1.2. Compiler Switches 80 

5.2. COMBAT 83 

5.2.1. User interface 83 

5.2. 1.1. Symbolic input 84 

5.2. 1.2. Filenames 84 

5 .2.1.3. Text 85 

5.2.2. Combat Questions 85 

5.2.3. Requesting Compilations 87 

5.2.4. ’I low to Run’ Options 90 

5.2.5. User Tailoring 90 

5.2.5. 1. Tailor files 91 

5.2.5.2. Create type 91 

5.2.5.3. Print type 92 

5.2.5.4. Delete type 92 

5.2.5.5. Alter type 92 

5.2.5.6. Load tailor. Replace tailor 92 

5.2.5 J. Xerox tailor 92 

5.3. The Compiler (Internals) 92 

5.3.1. How it Works 93 

5.3.1. 1. COMPILE and COMPILE-GROUP 93 

5.3.2. Modeling Pass 94 

5.3.3. Analysis Pass 95 

5.3.4. The Type Analysis Model % 

5.3.5. Life-and-Dcath Analysis 97 

5.3.6. Hie Variable Allocation Pass 97 

5.3.7' Hie Code Generation Pass 98 

6. Making It Run Faster 103 

6.1. GLUE 103 

6.1.1. How to Glue 103 

6.1.2. GLUE as a Program 104 

6.2. Glue Bits 105 

6.3. PDUMP 105 

6.4. SUBRFY 106 


Table of Contents 



IV 


lhc Ml)L Programming Environment 


6.5. Purification 107 

6.5.1. Purifying RSUBRs 108 

6.5.2. Purifying an Environment 109 

6.5.3. Purification Summary 110 

6.6. TEMPLATES 110 

6.6.1. Use of TEMPLATES 111 

6.6.2. Assembly of TEMPLATES 113 

7. The Assembler 115 

7.1. The Assembler 115 

7.1.1. General Organization 115 

7.1.2. The Assembler as a Program 116 

7.1.3. Format of Assembler’s Source 1 16 

7.1.4. Instruction Assembly 116 

7.1.5. Initial Symbols 117 

7.1.6. Macro Writing 117 

7.1.7. Pseudo Operations 118 

7.1.8. Ihc Type RSUBR 120 

7.1.9. Writing Gluable RSUBRs 121 

7.2. Debugging Binary Code 121 

7.3. Unassembling Binary Code 122 

8. informational Aids 125 

8.1. File Comparison and Checking with MUDCOM 125 

8.2. The MOL Listing Program MAT 126 

8.2.1. MAT Switches 127 

8.2.2. Subtitles 128 

8.2.3. MAI’ Definition 128 

8.2.4. MAT Record Files 131 

8.3. The MDL-IPC Device Interface MUDINQ 131 

Index 135 


Table of Contents 



The MDL Programming Hnvironment ' 


l 


INTRODUCTION 

Hie Mdl language is described in ‘1’hc Mdl Programming language’ [3], but in addition to the language 
itself, there is a rich and varied collection of software written in the language which facilitates the writing of 
programs and systems of programs in Mdl. Hie information describing this programming environment has 
been contained in various documents, some out of print or out of date, and in supplemental disk files 
describing changes and additions. Some of the packages of functions used to deal with Ml>l. code have never 
been formally documented. This manual brings together some of that scattered documentation. 

The document’s purpose is to flesh out the description of the language contained in The MDL 
Programming Language,' giving a fuller description of the program writing and debugging aids available to 
MDL users, to describe the methods for producing code usable by others, to describe the M I )l compiler and 
the many other techniques for producing and speeding up Mdi. object code. 

Hie imagined reader of this document is someone who has read "ITic MDL Programming Language,’ and 
now proposes to write programs in Mdl, possibly even very large programs. Mdl packages that he would 
find useful in the process of doing so arc documented here: editors, debuggers, etc. Packages that he might 
wish to use within his program arc not included: data-management systems, command interpreters, etc. 

This document is of necessity highly self- referent, as many of the components of the Mdi programming 
environment refer to each other and adhere to the same conventions. Additionally, this document assumes 
that the reader is familiar with the language itself (at least to some degree) and with the I TS, TF.NEX, or 
TOPS-20 operating systems. 


INTRODUCTION 



I'hc MDI. Programming Knvironment 


2 


ACKNOWLEDGMENTS 



I hc M 1)1. Programming Hnvironmcnt 


3 


ACKNOWLEDGMENTS 

The programs described in this document arc the products of many man-years of effort by many people. 
Most have been ‘touched’ by several programmers, added to and improved over the years. 

Some of the people responsible for the programs mentioned in this document arc: Chris Reeve (Mm , the 
compiler, GLUE); Brian Berkowitz (Ml)l., the compiler, TEMPLATE, SUBRFY); Bruce Daniels (Mm., the 
compiler. PACKAGE, PPRINT, DEBUGR, ASSEM); Tim Anderson (PACKAGE, the Library, FINDATOM, DFL, 
Combat, Mudinq); Neal Ryan (EDIT, PDUMP, the IPC interface); Marc Blank (Mat, Muix.om, MONITR, 
Combat, EDIT, CURSOR); David Lebling (CRITIC, EDIT); Michael Broos (the Library); Roger Banks 
(TRACE); Greg Pfister (PPRINT); Joel Berez(EDIT). 

(Most of the documentation subsumed in this manual is from published and unpublished memos of the 
Programming Technology Division of the M.l.T. Laboratory for Computer Science. As a general rule, 
updates and revisions to this and other PTI) documents concerning Ml)l. arc available online in the directory 
"MUDMAN" at MIT-DMS). 


ACKNOWLEDGMENTS 



The M 131 . Programming Hnvironment 


4 


NOTATION 



The M 1)1. Programming Knvironment 


5 


NOTATION 

Anything which is written in the Mm. language or which is typed on a computer console appears herein in 
a typewriter font, as in PPRINT. A mctasyntactic variable -- something to be replaced in actual use by 
something else -- appears as channel, in an italic font. Where a meta-syntactic variable is being used to denote 
a required argument to some function, it appears as before, but underlined, as channel . 

In the argument templates of Mm. functions, the individual arguments arc often given in the form 
argument: type, where argument is a descriptive' name for the argument, and type is its Mm type (or range of 
types). In such eases, the ‘type’ boolean indicates an argument that is only examined for truth or falsity, and 
not for any of its other qualities. Such arguments in Mm. arc often dcclarcd'<OR ATOM FALSE>\ 

Finally, file names are given as though for the ITS operating system: 
device : sname ; fnm / fnnt2 

Hie analogous specification for TF.NRX or 101*8-20 would be 
device: <sname>fnml .fnm2 

Note that in the THNKX/TOPS-20 version of Mm, the fnm2 (which may include the generation number, 
protection and acct tn) fields) is by default "MUD" as opposed to M > M for the ITS version. 


NOTATION 



6 


The MI)L Programming Hnvironment 


1.0 



The MDI. Programming Knvironment 


7 


1 . Overview of the MDL Programming 
Environment 

'Hie parts of the Mix, programming environment described in this document arc primarily those dealing 
with the writing, debugging, sharing, and maintenance of code and programs written in Ml)l.. Most of the 
packages described herein arc written in Mdi themselves; some arc assembly language programs useful to 
Mdi programmers. 

The document is divided into chapters dealing with the major issues facing the novice (or even the 
experienced) Mm, programmer. 

- ‘The Package System’ introduces the standard mechanism for lexical blocking and therefore, 
sharing of M 1)1. code. Understanding its use is fundamental to writing Mni, programs. 

- ‘Program Writing and Debugging Aids’ is the largest chapter. It covers mechanisms for loading, 
dumping, editing, and debugging Mdi. code, whether interpreted or compiled, in a development 
or a production environment 

- ‘The Library System’ discusses the usage of libraries of Mdi programs. 

- ‘The Compiler’ includes the specifics of interaction with the Mdi compiler, as well as an overview 
of the theory behind its operation. 

- ‘Making It Run Faster’ covers the various methods for speeding up ‘production’ Mdi. code by 
removing mediated calls and compacting data structures. 

- "Hie Assembler’ documents the Mdi. assembler and some methods of debugging binary code. 

- ‘Informational Aids’ discusses a few programs, most written in assembly language rather than 
Mdi., which arc useful to the Mdi. programmer. 


1.0 



Ilic M 1)1. Programming Environment 


2.0 



The MDI, Programming Environment 


9 


2. The Package System 

The portion of the Mm. environment which -provides a uniform facility for lexical blocking is known as the 
Package System. In one sense it is the most basic part of the environment, since it enables many programmers 
to use each other's code without identifier conflicts. 

In addition, the Package System is interfaced to a library facility (see section 4) by which Mm. code may 
be stored and later loaded as needed. 

The Package System is so basic to use of the Mm environment that (with a few exceptions) every 
subsystem or family of Mm. functions described in this document is a ‘package’. 

2.1 . The Theory of Lexical Blocking in MDL 

Lexical blocking is implemented in M 01 by means of OBLISTs and LISTs of OBLISTs. Changes of 
lexical context are performed using the SUBRs BLOCK and ENDBLOCK. The Package System provides a 
high-level interface to these low-level constructs. 

The primary goal of a lexical blocking scheme is the prevention of identifier conflicts. Specifically, when 
your program references the variable X, it should be your X and not that of some other program. At the same 
lime, it should not be necessary fora programmer to search every program previously written to verify that an 
identifier he wishes to use is not already ‘taken’. 

It should be clear that the simplest solution, a single OBLIST, will not satisfy either of these goals. With 
only one OBLIST there would necessarily be identifier conflicts, necessitating exhaustive searching for unique 
identifiers. 

Obviously, programmers could put their program’s identifiers on an OBLIST unique to that program. 
Unfortunately, such a solution addresses only half the problem. What happens when some other programmer 
wishes to use some of this code? He could insert the unique OBLIST for that program into the OBLIST path 
for his program; but the moment that is done he gets all the identifiers for that program, including local 
variables, internal data structures, and so on. 

Consequently, we move to a situation where each program uses two OBL ISTs; one for the identifiers that 
arc local to the program, and one for the identifiers that arc to be used by other programs. In the Package 
System, these are known as the ‘internal’ OBLIST and the entry’ OBLIST. 

Most of the identifiers in a program arc local to it, and want to be placed on the internal OBLIST. 


2.0 



10 


The Ml)l. Programming Knvironment 


Therefore, in terms of an argument to the BLOCK SUBR, when a program is being loaded into Mm,, the 

OB L I ST path wants to be: 

( internal- oblist 
entry-oblist 
<R00T> ) 

With this OBLIST path, most ATOMS (identifiers) will be on die internal OBLIST (as READ puts unknown 
identifiers on <1 .0BLIST>), but the ATOMs for die entries and the ATOMs for the usual SUBRs will be 
available. 

'rhe only issue yet to be addressed is that of using an entry of a different program in your program. This is 

accomplished by adding die entry OBLI STs of any such programs to the path after ROOT : 

( intcrnal-oblist 
entry-oblist 
<ROOT> 

other program-entry-oblist 
yet-anotherprogram-cntry-oblist 

• ) 

As only the entry OBLIST, and not the internal OBLIST, of the program being used is added to the path, 
the chance of identifier conflict is lessened. 

All that remains is to introduce the functions by which these various operations arc performed. 

2.2. Package System Overview 

The functions which make up the Package System are: * 

— PACKAGE. This indicates the start of a package of functions. 

— ENDPACKAGE. This indicates the end of the package of funedons. 

— ENTRY. This indicates an ATOM which is to be made available outside the definition of this 
package of functions. All other AT OMs will not be directly available outside the package. 

— USE. This indicates a reference by name to another package of functions. 

— USE -DATUM. This indicates a reference by name to a data seL 

— DROP and L -UNUSE. These undo the effects of USE and USE-DATUM. 

These functions arc themselves part of a package named " PKG", which is prcloadcd into Mol 


'ITic Theory of Lexical Blocking in MDL 


2.1 



The Ml)l. Programming Environment 


11 


2.2.1. Sample PACKAGE 

A sample M ni. PACKAGE is given with comments in order to demonstrate the usage of these functions. 

<PACKAGE "HOUR-STRINGS 

; "PACKAGE begins the package called HOUR-STRING." 

<ENTRY TIME-STRING> 

;"The atom TIME-STRING is an entry to this package; 
it may be referenced by other packages by 
USEing HOUR-STRING." 

<USE "DATIME"> 

;"Indicate that the package DATIME is 
used within the current package." 

<DEFINE TIME-STRING () 

<STRING <UNPARSE <H0URS>> " o'clock")) 

•."Define this little function which returns a string 
telling the last hour in a strange format." 

<DEFINE HOURS () <1 <RTIME>» 

;"Define an internal function which is available 
only within the HOUR-STRING package, since its 
name is not in any ENTRY statement. 

Note that this function refers to RTIME, 
which is an ENTRY in the DATIME package." 

<ENDPACKAGE> 

;"The end of this little demonstration package." 


2.3. PACKAGE 

This function delimits the beginning of a package of functions. It takes one required argument, a STRING, 
which is the name of the package. This STRING uniquely identifies the package within a library of packages 
(sec section 4). 

In a PACKAGE those ATOMS which arc specified as entries live in a separate OBLIST of their own, called 
the entry OBLIST. The ATOM naming this OBLIST is on the PACKAGE OBLIST and has the same name as 
the PACKAGE itself. Thus, an entry . ‘X' of a PACKAGE ‘Y’ would have as its ‘full-trailer’ name: 
X 1-Y1 -PACKAGE 1- . 

PACKAGE blocks (sets up) the current OBLIST path so that the ATOMs which arc internal to the PACKAGE 


2.2 


Package System Overview 



12 


The M 1)1. Programming Hnvironment 


fall into an OBLIST which is not otherwise used. The ATOM naming this OBLIST is on the entry OBLIST of 
the PACKAGE, and is by default given a name created by putting the character T at the beginning of the 
PACKAGE'S name. An internal ATOM 'T in the PACKAGE *Y' previously mentioned would have as its 
‘full-trailer’ name: Zl-IY! -Y! -PACKAGE!- . 

PACKAGE also keeps track of the fact that the particular PACKAGE named has been defined in this Mdl 

process, by putting its name on the PACKAGE OBLIST. 

<PACKAGE name: st mw 
iname:string 
size:Jix 

isize:fix> 

PACKAGE takes three optional arguments in addition to the required one (the optional arguments are 
ignored if name is already a PACKAGE): 

inamc is the name of the internal OBLIST of the PACKAGE; by default it is the name of the PACKAGE with 
the letter ‘I’ prefixed. 

size is the number of buckets in the entry oblist; by default 19. 
isizc is the number of buckets in the internal oblist: by default 23. 

In addition to PACKAGE, there exists the obsolete function RPACKAGE, documented here only because 
some programs still use it. Tlic difference between them is that the 01107 OBLIST for an RPACKAGE is the 
ROOT OBLIST. The implication of inserting an entry into the ROOT is that this requires that tlic name of the 
entry be unique over all PACKAGES, because the entry is, in effect, being promoted to the status of a SUBR. It 
is (in rare eases) useful to do this, but the correct way is with the function RENTRY (see section 2.3.1). 

2.3.1. ENTRY 

'Ibc ENTRY function applied to one or more ATOMS declares that these ATOMS arc to be put into the 
OBLIST reserved for entries in this particular PACKAGE. Only ATOMS declared in this way will be accessible 
(in the normal course of events) to functions outside this PACKAGE. 

It is possible to place some entries of a PACKAGE on the ROOT OBLIST using die function RENTRY. It is 
recommended that instead of using RPACKAGE in those rare eases where entries must go on the ROOT, 
RENTRY be used instead. 

All ENTRY statements should appear immediately after the PACKAGE or RPACKAGE statement Note: 
never put a USE statement before the ENTRY statements; if you do, you may get the ERROR message 


PACKAGE 


2.3 



The Ml)l. Programming Environment ' 


13 


ALREADY-USED-ELSEWHERE, meaning that the name of an entry is conflicting with an ENTRY in one of the 
PACKAGES you USEd. ENTRY will also give an ERROR if it is used outside the body of a PACKAGE. 

2.3.2. USE 

This function lakes as arguments one or more STRINGS which arc the names (as given to PACKAGE) of 
other PACKAGES. EXTERNAL is a synonym of USE. USE causes the entry 08L ISTs of the PACKAGES named 
to be spliced into the current OBLIST path. Thus, references to entries of those PACKAGES may be made 
after the USE, until the next ENDPACKAGE (or the next DROP or L-UNUSE if USE is being invoked outside a 
PACKAGE to load a file). 

USE is consequently the mechanism for sharing code. If the PACKAGE being used is already loaded, its 
entries arc made available; if not. the PACKAGE is loaded first (see section 4.1 for details on how this is 
accomplished). 

2.3.3. USE-DATUM 

USE -DATUM requires one STRING argument, the name of a data set. If the data set is not loaded, 
USE-DATUM loads it and creates an ATOM of the same name, on the USE-DATUM OBLIST, whose GVAL is the 
data set. USE - DATUM always EVALs to the data set named, regardless of whether it had to be loaded or not 

2.3.4. DROP and L-UNUSE 

These functions take the same arguments as USE and USE-DATUM and undo their effects. 

DROP simply splices the named PACKAGES out of the current OBLIST path. A USE of a DROPped 
PACKAGE will not reload the PACKAGE but simply splice it back into the OBLIST path. 

L-UNUSE splices the PACKAGE out and removes its name from die PACKAGE OBLIST, which will cause 
the entire PACKAGE to be reloaded if it is USEd again. L-UNUSE of a data set will remove its AT OM from the 
USE-DATUM OBLIST. 

2.3.5. ENDPACKAGE 

Hie ENDPACKAGE function of no arguments terminates the definition of die current PACKAGE and 
undoes the lexical blocking done by the PACKAGE function. 'Hie ENDPACKAGE statement should be the last 
one in the file. 


2.3 


PACKAGE 



14 


The Mill. Programming Environment 


2.3.6. PACKAGE Restrictions 

ITicrc arc some restrictions on what the user may do inside a PACKAGE. These arc enforced by the Library 
System when the user attempts to submit a PACKAGE to a library. 

A PACKAGE should not FLOAD or LOAD any file to obtain parts of itself. All such environment setup 
should be done with USE and USE -DATUM. 

A PACKAGE may not reference any ATOM whose OBLIST path goes through the INITIAL OBLIST. All 
of a PACKAGE'S non-entry ATOMs should fall naturally into the PACKAGE'S internal OBLIST. 

As mentioned before, die RENTRYs ofa PACKAGE have the same OBLIST status as SUBRs, i.c., they must 
be unique among both all SUBRs and all PACKAGE entries. 

2.3.7. ENTRY Name Conflicts 

It is possible to have two or more PACKAGES (not RPACKAGEs) which have entries (not RENTRYs) with the 
same PNAME. If the user needs bodi PACKAGES at the same time, he may USE them both and refer to the 
ambiguous entries by their ‘full trailer’ names. All of the non-ambiguous entries in both PACKAGES may still 
be referenced by PNAMF only. 


PACKAGE 


2.3 



The Mill. Programming Knvironmcnt 


15 


3. Program Writing and Debugging Aids 

Hi is chapter concentrates on editing and debugging aids for Mm programming. The basis for editing and 
debugging in Mdi. is twofold: First, Mdl is an interpreter, which permits interactive testing and debugging 
of software. Secondly, Mm. programs (even compiled Mni. programs) arc structures and therefore may be 
manipulated by other Mi)i. programs. 

Packages useful in editing and debugging range from EDIT and PPRINT, which arc prcloadcd, and which 
form the core of most editing or debugging systems, to more sophisticated aids such as DEBUGR and TRACE, 
which arc more powerful, and useful for more complicated debugging. 

It should be noted that, in addition to the editors discussed below, Rmodi [5] and I'M ACS [2], TlX'O based 
text editors, understand much of the syntax and many of the conventions of Mix. programs. 

3.1. Pretty-Printing 

The purpose of pretty printing is to clarify the structure of Mm. objects by printing them in a more 
human-readable format than that provided by the SUBRs PRINT, PRIN1, etc. Objects are pretty-printed 
through the judicious insertion of spaces, tabs, and ncw-lincs between tokens. Pretty-printed objects are 
readable by the Mm. Reader. Pretty printing is an aid to understanding and debugging Mm FUNCT IONS or 
other objects. You will probably find pretty printing to be extremely helpful, especially if you arc working 
without a listing or with an old listing. In fact, pretty-printing is one way to make a new pretty listing after 
editing. PPRINT is pre-loaded in most initial M 1)1 s. The name of the package containing PPRINT is"PP". 

< PPRINT (jm channel 

pretty-prints any on channel. The second argument is optional, by default .OUTCHAN . If any is an ATOM, 
PPRINT will enclose it in an application of DEFINE, DEFMAC, SETG, or SET, as seems appropriate. 
COMMENTS found inside any arc right-justified. PPRINT cannot output an RSUBR without FIXUPs (that is, 
one that was READ in while KEEP-FIXUPS (see section 3.4) had no LVAL or had a FALSE LVAL); it will 
give the ERROR message CAN-NOT-BE-DUMPED. PPRINT returns .NULL, which is an ATOM whose PNAME 
is a single rubout, invisible on normal consoles. 

<PPRINF in:striiie-oratom-orlist outfile: string 
widfh.fix eval?:boolean> 

pretty-prints all the contents of in into outfile. 

If in is an ATOM ora LIST of ATOMS, its VALUE(s) arc the objects to be PPRINTed. In tins ease, outfile is 
by default a file whose first name is produced by Liking the PNAME of in (or ins first element if in is a L 1ST). 


3.0 



16 


llic Ml)l. Programming Environment 


If in is a STRING, if specifics a file containing objects to PPRINT. In this ease, outfile is by default 
"TPL:\ 

width is the maximum width of output lines (although output lines are prevented from being extremely 
long); it is optional, by default <13 ,OUTCHAN>. 

eval? tells PPRINF whether or not to EVAL everything in the file; it is optional, by default a FALSE (don't 
EVAL). eval? is meaningless if in is not a STRING. 

PPRINF returns either "DONE" or a FALSE if it couldn’t open injile or outfile. PPRINF inserts page 
boundaries in outfile . , between objects, every 60 lines or fewer; you may want to move these afterward to more 
logical places. PPRINF binds KEEP-FIXUPS and REDEFINE to T, and QUICKPRINT (see below) to a 
FALSE. 

3.1.1. PPRINT Control Switches 

PPRINT’s output is affected by the local values of several ATOMs. Each value is examined only for truth. 
.QUICKPRINT 

If tli is ATOM'S LVAL is a FALSE, you arc in slow mode; otherwise (including the ease of no LVAL), you are in 
fast mode. ’Hie behavioral difference is this: in fast mode, there may be COMMENTS in the pretty-printed 
objcct(s) which PPRINT misses. Also, fast mode is indeed faster than slow mode. Fast mode is the default, 
that is, QUICKPRINT is initially true. ’Hie modes arc really distinguished by the depth of recursion to which 
PPRINT resorts. In slow mode, it rccurscs all the way down to every monad in the thing pretty-printed; in 
fast mode, it goes down only far enough to find something that will fit on a line. 

.LOOKAHEAD 

PPRINT uses full recursive lookahead to avoid packing things against the right margin and, as a result, not 
being able to fit things within the right margin. 'The lookahead results in very good formatting of 
deeply-nested MAPFed and FUNCTIONS; all but the most bizarre cases should be very legible. However, it 
can result in noticeable ‘pauses’ in the printing operation and, in some eases, a net speed slightly less than with 
limited lookahead. Since this can be a disadvantage when using PPRINT interactively on a heavily-loaded 
system, the Imikahcad can be disabled: if the LVAL of LOOKAHEAD is a FALSE, no lookahead will be 
performed; otherwise it happens. LOOKAHEAD is initially true, that is, lookahead happens by default 
.VERTICAL 

If LOOKAHEAD is a FALSE, the formatting can cause too many objects to be squeezed against the right 
margin. So that particular eases can be made legible, the format when lookahead is not in use can be 
manually set; if the LVAL of VERT ICAL is non-FALSE, PPRINT will indent very little whenever indenting is 


Pretty-Printing 


3.1 



The M 1)1. Programming Fnvironment 


17 


called for. (VERTICAL being true means a ‘more vertical' format.) VERTICAL is initially FALSE . The value 
of VERTICAL is ignored when LOOKAHEAD is true; the lookahead effectively chooses different values for 
VERTICAL for different parts of the object pretty-printed. 

3.1.2. Lower-level Pretty Printing 

It is sometimes desirable to use some of the functions that PPRINT uses, but in a different way. For 
example, a specialized pretty-printer for Program Abstracts would want to insert indented field names into 
the output and pretty-print field values with the same indentation. The names of lower-level pretty-print 
functions arc included in the ROOT OBLIST for such purposes. 

<EPRINT anv lcfi-margin:fix> 

pretty-prints any on .OUTCHAN to the right of left-margin. The second argument is optional, by default 
CVALUE LEFT-MARGIN> (see below). 

<EPRIN1 anv lcfl-margin:fix> 

EPRIN1 is to EPRINT asPRINl is to PRINT. 

.LEFT-MARGIN 

This is the ATOM that EPRINT binds to its second argument. You can SET it outside calls to EPRINT in order 
to make a permanent left margin. Its initial LVAL is 0 . 

< INDENT -TO column: hx channet> 

outputs Libs and/or spaces to advance the output column (< 14 channeb) to column , if it is not already past. 

<C0LPP anv 

channel 

left- margin: fix 
right-margin:fix> 

pretty-prints any on channel (by default .OUTCHAN) between the margins left-margin (by default 
<14 chatweb, the current column) and right-margin (by dcfault<13 channeb, the rightmost column). All 
arguments but the first arc optional. COLPP returns .NULL. For example, 

<C0LPP any .OUTCHAN 10 70> would leave a 10-character margin at left and right on an 80-column 

OUTCHAN. Also, 

<PR0G () <PRINT AAAAAAAAAAAAAAA> <COLPP ,FOO>> 
would result in output like 

AAAAAAAAAAAAAAA //FUNCTION ((X GGGGGGGGGGGGGGGGGGGGGG ) 

<+ X 1>) 

EPRINT, EPRIN1, and COLPP arc affected by the truth of .QUICKPRINT, .LOOKAHEAD, and 
.VERTICAL. 


3.1 


Pretty-Printing 



18 


I hc Mill. Programming Environment 


3.1.3. Ampersand Printing 

'Ampersand printing’ consists of printing any object on a single line by using the character & (ampersand) 
to mean ‘There's more stuff here.’ ('Phis technique is borrowed from the interLisp editor.) 

There arc two ways in which & is used by this printer as an abbreviation: 

1. An & appearing between some variety of brackets indicates 'that there is a big object of the 
indicated TYPE there. 

2. TTtc characters . . & or & . . on the left or right of a structure mean that there arc more objects to 
the left or right which have not been printed. 

Examples: 

^FUNCTION ((A BCD) <&>) 

T his is a FUNCTION with four arguments in its argument LIST, and the FUNCTION body contains one FORM 
which was too big to print in the remainder of the line. 

<PROG () <KRK <+ .A 5>> <PRINC .Q> <SET BAR <0RG>> <8r> &..> 

This is a large FORM, namely, a PROG. In addition to the elements printed, there arc more elements to the 
right, and there is one FORM which was too big to fit 

Ampersand printing is effected by two pure RSUBRs: &, analogous to PRINT, and &1, analogous to 
PRIN1. A related RSUBR, &LIS, can be applied to no arguments to put you into an endless READ-EVAL-& 
loop, instead of the normal READ-EVAL-PRINT loop. 

3.1.4. Examining the Stack 

<FRM fe> 

returns the fix th FRAME down from the top application of ERROR or LISTEN. 

< FRAMES howmany:fix slart:fix> 

pretty-prints how-many FRAMES (by printing the FRAME number (suitable as an argument to FRM), FUNCT, 
and ARGS of the FRAME), starting with <FRM siart> . Both arguments arc optional; start defaults to 0, and 
how-many defaults to a large integer. A FRAME whose FUNCT is an ATOM whose VALUE is an FSUBR is not 
printed, if the same information is found in the next lower FRAME . 

<FR& how-many:fix start :fix> 

is like FRAMES but uses ampersand printing instead of pretty printing. It is handy for summarizing FUNCTs 
and ARGS that arc Large or unprintable (like RSUBRs with no fixups). 


Pretty-Printing 


3.1 



The MDI. Programming Knvironment 


19 


<FRATM how- many: fix siarl:fix> 

is like FRAMES but gives an abbreviated view of the stack. It prints FUNCTs only, and only for FRAMES 

connected with named FUNCTIONS, RSUBRs, and RSUBR-ENTRYs, It is handy when a FRAME contains a 

non-LEGAL? object. 

<FRLVAL atom 

how-many:fix 

siari:fix> 

prints out the stacked bindings of atom , going through how-many FRAMES, starting with <FRM start). The 

two numeric arguments arc optional; how-many defaults to a large integer, and start defaults to 0. TTie 

fonnat of the printing is two columns: the first column is the number of the FRAME in which atom has a 

binding; the second column is the value bound, or a message proclaiming die lack of a value. 

<FR&VAL aim 

hoiv many: fix 
slarl.fix > 

is precisely the same as FRLVAL, except that the values arc ampersand printed instead of PRINTed. 

Finally, the "FRMSP" PACKAGE contains analogues of many of the preceding functions, but each takes as 
its first argument a PROCESS, by default <ME>. These arc all named by adding a ‘P’ to the cud of the usual 
name. For example, 

<FR&P <MAIN» 

doesa <FR&> in the PROCESS MAIN. 

There is one additional function of interest in "FRMSP". 

<FRTYPE how-many:fix start:ftx> 

is like FRAMES, but gives only the TYPES of the arguments to each. This is useful in those situations when die 
stack shows illegal FRAMES or other unprintable objects. 

3.2. The MDL Editor 

EDIT allows a MDL user to make incremental changes in MDL structured objects, without leaving Mdl 
and with the ability to save the results in a file, and to set or clear conditional breakpoints of various sorts in 
objects that will be evaluated, such as FUNCT IONs. 

EDIT is an editor/debugger written in, written for, and running under MDL. It comprises the package 
"EDIT" and several smaller packages which will be mentioned later in diis section. EDIT is prcloadcd in 
most initial MDLs. 

To start editing, apply EDIT to no arguments or to the name of the object you wish to edit: <EDIT> 


3.1 


Pretty-Prindng 



20 


The MDL Programming Knvironment 


causes entry into EDIT and opens the last object edited; <EDIT object > causes entry into EDIT and opens 
object for editing. Permissible objects include; 

- ATOHs. The GVAL (preferably) or the LVAL of the ATOM is opened. If it has no value, EDIT 
returns a FALSE. 

-APRIMTYPE LIST. ThePRIMTYPE LIST isopened. 

- A FIX. The stack frame with that number is opened (i.c.,< A RGS <FRM fix»). 

Part of EDIT's efficiency comes from forbidding it to delve into objects that are not of PRIMTYPE LIST, 
that is, not LISTs, FORMs, FUNCTIONS, etc. Attempts to edit objects of other PRIMTYPEs will result in error 
messages. These objects can, however, be treated as units when inserting, searching, etc.; or they can be 
changed into LISTs, edited, and then changed back to their original types. 


3.2.1. The Edit ’LISTEN Loop’ 

3. 2. 1.1. The Reader 

When in EDIT, you arc typing at a special, non-standard, input function: The EDIT Reader. 

The Reader allows you to type EDIT commands and have them executed, and also to evaluate Mdl 
expressions normally. Its characteristics arc as follows: 

— As in the normal Mdl Reader, nothing is done until you type ESC. DEL, tL, tD, tG, and tS also 
work normally. 

— All EDIT commands arc terminated when an ESC is encountered in the input stream. In 
addition, most commands will terminate whenever the maximum number of arguments required 
has been input or whenever an argument of the wrong type is encountered. In the former ease the 
next object is taken as a new command; in the latter ease the object of the wrong type is taken as a 
new command. EDIT commands may be typed in either upper or lower case. 

— If you type something that EDIT docs not recognize as a command, nonnal Mdl evaluation and 
printing arc performed on that something. This evaluation will have no effect on your position in 
the object you arc editing. 

— While editing a function which is part of a PACKAGE (determined from an examination of the 
OBLIST containing the ATOM whose value is the function), EDIT causes the OBLIST path to be 
set up to what it was in the environment of that PACKAGE. This has the advantage of reducing the 
number of trailers printed, and causes newly entered ATOMS to fall on the correct OBLIST (the 
internal OBLIST of the PACKAGE). It has the slight disadvantage that it disables the dynamic 
loader (which depends on unbound variables falling on the INITIAL OBLIST). If the GVAL of 
E-PKG is a FALSE, this feature is disabled, and the nonnal OBLIST path is in effect during 


The MDL Editor 


3.2 



The MDL Programming Hnvironment 


21 


editing. 

Examples: 

R 5$ 

Causes execution of EDIT command R, with argument S. 

<R 5>$ 

Causes application of die function R to 5. 

3. 2. 1.2. The Ampersand Printer 

Your current position is displayed by 'ampersand printing’ (see section 3.1.3). This consists of printing any 
object on a single line by using the character & (ampersand) to mean ‘'ITicrc’s more stuff here.’ 

The ampersand printer used in EDIT is much like the standard one, with the addition that your current 
position (Sec below) is displayed by the glyph I. 

When you initially enter EDIT, you arc in a inode called ‘non-verbose,’ in which ampersand printing is not 
automatically done following execution of ED IT commands. The V command is used to toggle you in and out 
of verbose mode (see below). 

Examples: 

^FUNCTION ( ■ (A B C D) <&» 

Indicates diat your position is just to the left of a FUNCTION'S argument list, and the FUNCTION body 
contains one FORM which was too big to print. 

<..& <KRK <+ .A 5>> I <SET BAR <0RG» <&> &..> 

Indicates that you arc in the middle of a large FORM (c.g., a REPEAT or a PROG), positioned just to the left of 
the < SET BAR <0RG>>. In addition to the objects printed, there arc more objects to both the left and the 
right, and Uicrc is one FORM which was too large to fit on the line. 

3.2.2. Edit Commands 
3. 2. 2.1. General 

A sequence of EDIT commands is executed as soon as you type ESC. If one command fails, subsequent 
commands up to the ESC arc ignored, and EDIT types out an appropriate error message. A failing EDIT 
command generally has no effect whatsoever; but see individual descriptions. 

Note that all arguments to EDIT functions must be legal Moi. objects. In particular, you can’t search for 


3.2 


Hie MDL Editor 



22 


llic Ml)l. Programming Environment 


<SET , since the O’s aren’t balanced Nor can you insert it. (But you can, for instance, search for and insert 
<SET THING 1>.) 

If a command expects an argument and doesn’t get one, an error message will be printed. 

Many EDIT commands take FIXes as arguments. Those that do interpret the ATOM * as an argument to 
mean ‘as many as possible’. 

Whenever you arc in EDIT, you have a well-defined ‘position’. A position is a ‘place’ inside a MDL 
structure; this ‘place’ is cither between two elements of the structure, or between an element and either end of 
the structure, or inside an empty structure. All editing, movement, and printing commands operate relative to 
your current position. The term ‘cursor’ is used in the following descriptions to refer to an embodiment of a 
position. 

The formal used in each of the following command descriptions is: 

Command as Typed English Name 

Description 

3. 2. 2. 2. General Commands 

? duh? 

Causes a short summary of all EDIT commands to be typed out. The same summary appears later in this 
chapter. 

?? huh? 

Similar to the above, but the summary is even shorter, and should fit entirely on the screen of an Imlac 
terminal. 

0 Quit 

Leave EDIT and return to Mm,. (Causes EDIT to return die ATOM T.) 

QR fix Quit and Retry 

Quit from EDIT and then retry the frame specified, or by default, the one originally given to an open 
command or, if none was given, the frame beneath the last ERROR or LISTEN frame. 
tF Control-F 

This is not really an EDIT command; rather, it is a character, obtained from die input stream at interrupt 


The MDL Editor 


3.2 



ITic Ml)l. Programming Environment 


23 


level, which is used to return you to the EDIT Reader from some higher level of application, c.g., an ERROR’S 
LISTEN. It is tlic EDIT equivalent of ERRET with no arguments. 

tF (or tS) typed during execution of ah EDIT command is similar to normal Mdl tS but returns to the 
EDIT Reader instead of the Mdl LISTEN loop. 

0 gbje£t Open 

Equivalent to Q followed by <EDIT objecO. Positions the cursor just to tlic left of the first element of the 
entire object specified. 

OT Open This 

If the object to the right of the cursor is an ATOM, or a FORM whose first element is an ATOM, and the 
ATOM’S value is opcnablc, then it is opened. This command js useful when tracing a calling sequence through 
several functions. 

3. 2. 2. 3. Movement Commands 

UT Up to the Top 

Places the cursor at the position it had following an 0. 

R fix Right 

Moves the cursor fix objects to tlic right, by default one. If fix is too large, i.c., there arc not that many 
positions to the right of the current position, EDIT prints an error comment and the cursor stays where it is. 

B Back 

Moves the cursor as far to (he right as possible. 

L fix Left 

Moves the cursor fix positions to the left, by default one. If fix is too large, EDIT prints an error message. 

F Front 

Moves tlic cursor as far to the left as possible. 

DL Down Left 

Positions the cursor just to the right of tlic rightmost element within the object to tlic left of the cursor, if 
that object isof PRIMTYPE LIST. Visually, tlic cursor moves left over one ‘close bracket’. 


3.2 


The MDL Editor 



24 


The Ml)l. Programming Environment 


DR Down Right 

Positions the cursor just to the left of,thc leftmost element within tire object to the right of the cursor, if 
that object isofPRIMTYPE LIST. Visually, the cursor moves right over one ‘open bracket’. If the cursor is 
to the left of an element that is. not of PRIMTYPE LIST, EDIT prints an error message. 

D Down 


Equivalent to DR. 

UR fix Up Right 

Positions the cursor just to the right of the object the cursor is currently within. Docs so fix times, by 
default once. 

UL fix Up Left 

Positions the cursor just to the left of the object the cursor is currently within. Does so fix times, by default 
once. 

U fix Up 

Identical to UL. 

S object Search 

Docs a depth-first, left-first tree-walk, (i.c., left-to-right) starting with the object to the right of the cursor, 
until the cursor is just to the right of an object structurally equal (i.c., =?) to its argument. An occurrence of 
the object will not be found if it is inside anything not of PR IMT YPE LIST. On failure, the cursor docs not 
move. I f the argument is omitted, the last object searched for is used. 

SR object Search Right 

Same asS. 

SL object Search Left 

Same as S, but the tree-walk is depth-first, right-first (i.c., right-to-lcfl) and you end up to the left of the 
object for which you were searching. 

3.2.2.4. Printing Commands 

The Empty Command 


The MDL Editor 


12 



The MDI. Programming Hnvironment ' 


25 


Causes the normal ‘ampersand print’ to be done. This is principally useful when you arc in ‘silent’ mode; 
see the V command. 

By the way, an ‘empty’ command is typed by typing ESC without having typed any visible characters 
before it 

P Print 

PPRINTs (not ‘ampersand prints’) die object to the right of the cursor. 

PU Print Up 

PPRINTs the object the cursor is in. This is similar to doing a U and then a P. although die cursor is not 
moved. 

. PT Print Top 

PPRINTs the whole object you have open. 

V Verbosity 

Toggles the verbosity mode between ‘verbose’ (most commands cause ampersand printing) and ‘silent’ 
(printing of any sort is done only when some explicit print command is used, or when an error occurs). The 
current state of verbosity is the GVAL of E - VE RBOSE. 

In silent mode, absolutely nothing is printed after each command, not even ncw-lincs or prompts. 
However, normal Mm. evaluation still causes normal Mdl printing. 

3 . 2 . 2 . 5 . Editing Commands 

I any . . . Insert 

Inserts all its arguments immediately to the right of the cursor. None of its arguments arc evaluated; you 
can insert uhevaluated FORMs without using QUOTE. The cursor ends up to the right of the last object 
inserted. 

G flag ... Get 

Same as I, but its arguments are evaluated. This is useful in conjunction with the X command (see below). 
I: lype:atom fix Insert Type 

Grabs fix objects to the right of the cursor, inserts them into a newly created object of TYPE type, deletes 
them from the original structure, and inserts die newly created object in their place. In other words, it ‘inserts’ 


3.2 


The MDL Editor 



26 


llie Ml)l. Programming Environment 


the appropriate open and close brackets for type at the cursor and fix objects to the righL 

Ry default fix is one, type is LIST. An error message is printed if fix is larger than the number of objects 
to the right of the cursor. 

Tlierc is no way to directly insert or delete single parentheses, brackets, etc., using EDIT. Instead, use K: 
(see below) to remove pairs of brackets, and I : to insert them. 

I* indicaloratom newstructure Imbed 

Imbed looks for all occurrences of indicator in iiew-stniciure and replaces these occurrences with objects 
Liken and deleted from the right of the cursor. It then inserts the result 

If only newstructure is given, the indicator is the ATOM *. If there aren't enough objects to the right of the 
cursor to replace each indicator , remaining indicators arc left untouched and a warning message is printed. If 
no indicators arc found, the new structure is inserted, but a warning message is printed. 

I* is generally used to insert one or more structures into another complex structure in one operation, 
instead of several. For example: 

<SET X ■ <12 . Y» 

I* <COND ( <N0T <LENGTH? .Y 11» •)>$ 

<SET X <COND ( <N0T <LENGTH? .Y 11» <12 .Y>)> I > 

places a protective conditional around an NTH to prevent an out-of-bounds error. 

IG Insert into Group 

Inserts into a group. IG is similar to I, but assumes that the object you arc in is a group (as produced by 
GROUP-LOAD). Arguments to IG which arc not ATOMS arc inserted as in I. Objects which are ATOMS and 
which have a value insert a FORM which DEFINES, SETGs, or SETs the ATOM as appropriate. TTius, to add a 
new function F to a group G, one could type 
0 GJIG FSQS 

K fix Kill 

Deletes fix objects to the right of the cursor. Defaults to one. Negative./?.* causes deletion to the left of the 
cursor. 

C aai Change 

Changes the one object to the right of the cursor to its single argument Docs not move the cursor. Docs 
not evaluate its argument C is more efficient than K plus I. 


The MDL Editor 


3.2 



Ihc Ml)l. Programming Environment 


27 


C: I m- alQm Change Type 

Changes the type of object to the right of the cursor to type. Attempts to do something reasonable for 
every type change. If you tell it to change a STRING to a LIST, you get a LIST of CHARACTERS. If you 
attempt to change a structure whose elements arc other than CHARACTERS and STRINGS to a STRING, you 
will get a Mol error. 

K: Kill Typo 

Deletes the brackets around the object to the right of the cursor. I.c.. kills the object and inserts its 
elements into the structure of which it was a part. 

SU U£E eld Substitute 

Hie Substitute command lakes two arguments. All occurrences of old from the current location to the end 
of the open object (actually a search-right is done) arc replaced by new. Once the search for old fails, the 
command terminates, and the numlrcr of substitutions performed is printed. T he cursor is left after the last 
object replaced. 

X atom Transfer 

SETs the atom to the object to the right of the cursor. X can be used with K and G to move things around 
within the object being edited. 

SW Swap 

Swaps the two objects to right of the cursor, leaving the cursor pointing at the same object. The effect is to 
move the cursor and the object it points at one object to the right. Repeated SWs move cursor and object 
further and further to the righL 

3. 2. 2. 6. Macro Facility 

M macro Macro 

Takes either a STRING or something which EVALs to a STRING and performs all of the commands in the 
STRING. For complete assurance that your commands will be done properly, put an ESC between 
commands. 

IT fijc macro Iterate 

r rhis command (also called DO) tikes a fix and macro as if an argument to M. Ill is command will loop 
through the macro fix times or until an error is generated. When the iteration ends, the user is told how many 


3.2 


The MDE Editor 



28 


The Ml)l. Programming Knvironment 


complete passes have been made of the macro. 

In both of the above commands, if an EDIT error is generated, the macro will be terminated, and the 
macro itself will be printed, with an arrow pointing to the offending command. 'Ilic cursor will remain at the 
place where the last legal command left it 

Hie SU command is, internally: 

DO * "S olJSLSC tiert” 

3. 2. 2.7. Cursors 

Cursors are locations in objects being EDITed. In addition to the main cursor, which is where editing 
occurs, other locations (also called cursors) may be remembered. Hie main cursor may be moved to another 
cursor in a single operation, potentially saving many motion commands. In large FUNCTIONS cursors may 
also reduce confusion by distinguishing among several similar areas of code. 

UC Use Cursors 

The PACKAGE for dealing with cursors is not normally loaded in an initial Mdl, so the UC command loads 
it and makes the cursor commands available. ’1116 PACKAGE loaded is "CURSOR". 

CU atom Cursor 

CU takes an ATOM argument and SETs the ATOM to an object of type CURSOR, which tries to be clever in 
the event you change the object. Also, if you use the X command to name a substructure and then move copy 
it with G or I, the cursors in the substructure will follow to the new location. 

There are some restrictions. Cursors in empty LISTs arc okay but they will not follow the object to new 
locations. Also this ‘following’ feature is effective only at the first G or I after the X. To move the substructure 
again you have to X again. 

I * is somewhat incompatible with CURSORS. Cursors in Imbedded structures will sometimes disappear. 

GO cursor Go 

GO takes a cursor (normally the LVAL of an ATOM previously given as an argument to CU) and GOcs to that 
position. If the cursor is illegal (not in the current top-level structure), an error message will be printed and 
you wilt remain in your previous position. 

KC atom Kill Cursor 


The MDL Editor 


U 



The M 1)1. Programming Hnvironment 


29 


K ill the cursor assigned to atom. 

PC ' Print Cursors 

Prints all cursors in the structure to the right of the main cursor. 

PA Print All Cursors 

Prints all cursors in the currently open structure. 

3. 2. 2.8. Breakpoints 

BK predicate any ... Breakpoint 

Inserts a breakpoint ‘around’ the object to the right of the cursor. Takes any number of arguments. 
Subsequently, whenever that object would have been evaluated, you instead hit a breakpoint function which: 

1. Hvaluates predicate. If the value is FALSE, evaluation continues as if there were no breakpoint. If 
the value is non-FALSE, or if BK was given no arguments: 

2. Types **BREAK**. 

3. For each argument after the first that you gave BK, types 

arg = FVALofarg 

4. Enters LISTEN. 

You continue by applying ERRET to one argument, just as from an ERROR; the argument’s value is ignored. 

Breakpoints arc implemented by inserting a BREAKR (a PRIMTYPE LIST with APPLYTYPE FORM) 
which consists of the function BREAKR and arguments, including the object breakpointed. A breakpoint 
prints as a glyph similar to the cursor: 

| object 

IfthcATOM SHORT-PRINT is assigned and FALSE, the actual BREAKR LIST is printed. 

ITic breakpoint function returns EVAL of the thing it is put ‘around,’ and there arc eases where this does 
not work. There arc always equivalent places that do work. 

1. Breakpoint on the first element of a F ORM docs not work. Put it on the whole FORM. 

2. Breakpoint on a LIST which is an argument to a COND docs not work. Put it on the first FORM in 
the LIST. 

BA predicate any ... Break After 


3.2 


The MDL Editor 


30 


The Ml)l. Programming Knvironment 


Similar to BK, but puts the breakpoint after the object at the cursor. Its action is like that of BK except that 
the break occurs after the object it is on is E VALed. 

This sort of breakpoint prints like the ‘before’ sort, but with the glyph after the object broken: 
object f 

'ITic predicate for a BA breakpoint may check the value returned by F % VAL for the object the breakpoint is on. 
'lliis value is assigned by BREAKR to the ATOM VALUE. 

KT Kill This 

Removes the breakpoint (if any) from the object to the right of the cursor. 

KB Kill Breakpoints 

Removes all breakpoints in the currently open object 

3.2. 2.9. Edit Monitors 

'lhcrc arc several commands in EDIT which provide a simple interface to the "MONITOR" PACKAGE. 
'Ihcsc allow placing of monitors on references to or modifications of LVALs in interpreted Mdi. code. 

For a more complete discussion of the use of monitors, see section 3.7. 

UM Use Monitors 

The PACKAGES for dealing with monitors arc not normally loaded in an initial Mdi., so the UM command 
loads them and makes the three commands for creating monitors available. The PACKAGES loaded are 
"MONITR", which is the general monitor PACKAGE, and "EMONIT", which is the interface between EDIT 
and "MONITR". 

RW glam predicate any ... Read-write Monitor 

The most general type of monitor that can be set is a read-write monitor. It will catch any reference to or 
attempt to modify the LVAL of the alum specified. The restrictions on placement of breakpoints also apply to 
monitors, with the addition that a monitor on an LVAL must be placed after that LVAL has become 
ASSIGNED?. 

The second, third (and so on) arguments to RW arc the same as those for BK. Ihc predicate may be 
dependent on either the new or old value of the variable: Ihcsc arc available as the LVALs of NEWVAL and 
OLDVAL, respectively. 


IheMDL Editor 


3.2 



The M 1)1. Programming Environment 


31 


When a monitor is triggered, it prints the type of monitor, the variable being monitored, and any other 
information requested by the user, and then calls LISTEN. 

A monitor prints as yet another glyph: 
l|l \_alom~\object 

where atom is the AT OM being monitored, and object is the object on which the call to MON I TOR is placed. 

Edit monitors arc objects of type BREAKR, and thus they arc killed by the same commands that kill normal 
breakpoints: KB, KT, and so on. 

RM atom predicate any Read Monitor 

RM is analogous to RW, but is only triggered by reading the variable. 

WM atom predicate any ... Write Monitor 

WM is analogous to RW, but is only triggered by writing the variable. 

3. 2. 2.1 0. User-defined Edit Commands 

It is possible to add user-defined commands to EDIT. The value of EDIT-TABLE should be a VECTOR of 
STRINGS (commands) and APPLICABLE objects. EDIT will search EDIT-TABLE before its own command 
table. If a match is found, the APPLICABLE will be applied to three arguments: the command string, the 
LOCATIVE containing the item currently being edited (the immediately surrounding object) and the position 
in that item. 

Note that user-defined commands should not be added except by constructing a new value of 
EDIT-TABLE from the commands to be added and the old value. Otherwise, any existing user-defined 
commands may be lost when new ones are added. 

The Monitor commands described in section 3.2.2.9 arc effectively ‘installed’ user-defined commands. 
They add elements to EDIT-TABLE when loaded by the UM command. 

3.2.3. Examples 

3. 2. 3.1. Simple Editing 

Suppose you have the FUNCTION 


3.2 


The MDL Editor 



32 


The M 1)1, Programming Knvironment 


//FUNCTION ((’A) <EVAL .A>) 

as the global value of the AT OM SIMP, and you wish to change it to 

//FUNCTION (("BIND" B 'A) (<EVAL .A .B> .A)) 

using EDIT. 'Ihc following example docs just that; it includes doing the editing and applying of SIMP to an 

argument. Console input and output arc shown below exactly as they would be in non-silent mode. (Console 

input consists of Uiosc characters to the left of every $). Note that there is nothing in SIMP which is big 

enough to warrant use of an &. 

<EDIT SIMP>$ 

VS 

//FUNCTION ( ■ (’A) <EVAL .A>) 

DS 

( ■ ’A) 

I "BIND" B$ 

("BIND" B ■ ’A) 

S .AS 

<EVAL .A ■ > 

I .BS 

<EVAL .A .B ■ > 

UR$ 

//FUNCTION (("BIND" B ’A) <EVAL .A .B> ■ ) 

I .AS 

//FUNCTION (("BIND" B ’A) <EVAL .A .B> .A I ) 

L 2$ 

//FUNCTION (("BIND" B ’A) I <EVAL .A .B> .A) 

I: LIST 2$ 

//FUNCTION (("BIND" B ’A) I ( <EVAL .A .B> .A)) 

<SIMP <+ 1 2»$ 

(3 <+ 1 2>) 

//FUNCTION (("BIND" B ’A) I (<EVAL .A .B> .A)) 

QST 


3. 2.3.2. X and G Commands 

In this example we have the FUNCTION 

< DEFINE F (X) 

<6 .X 10> 

<H 23 <- .X 1»>$ 

By applying the X and G commands to the appropriate FORMS, we arc able to swap the FORMS within the 
FUNCTION. 


11k MDL Editor 


3.2 



The M 1)1. Programming Environment 


33 


<DEFINE F (X) 

<G .X 10> 

<H 23 <- .X 1>»$ 

F 

<EDIT F>S 

$ 

^FUNCTION ( ■ (X) <G .X 10> <H 23 <- .X 1>>) 

R$$ 

^FUNCTION ((X) I <G .X 10> <H 23 <- .X 1^>) 

X MOVERS 

^FUNCTION ((X) R <G .X 10> <H 23 <- .X 1>>) 

K$$ 

^FUNCTION ((X) I <H 23 <- .X 1») 

R$$ 

^FUNCTION ((X) <H 23 <- .X 1>> R ) 

G .MOVERS! 

^FUNCTION ((X) <H 23 <- .X 1>> <G .X 10> H ) 
QST 

.MOVERS 
<G .X 10> 


3. 2. 3. 3. Unconditional Breakpoints 

To insert unconditional breakpoints into the FUNCTION in the next example, do the following: 

1. Define FIB and test the FUNCTION a few times. 

2. Kntcr EDIT and position the cursor appropriately. 

3. Insert the breakpoint 

4. Leave EDIT and run the FUNCTION again for the value 3. The breakpoint is exercised 5 times 
during this run. 


3.2 


flic MDL Editor 



34 


The Ml)l. Programming Environment 


<DEFINE FIB (X) 

<COND ( <L=? .X 1> .X) 

(ELSE <+ <FI8 <- .X 2» <FIB <- .X 1>!$ 

FIB 

<FIB 5>$ 

5 

<FIB 6>$ 

8 

<FIB 10>$ 

55 

<EDIT FIB>$ 

RS$ 

^FUNCTION ((X) ■ <&>) 

BK T . XSQJT 
<FIB 3>$ 

••BREAK** 

.X * 3 

LISTENING-AT-LEVEL 2 PROCESS 1 
<ERRET T>$ 

••BREAK** 

.X * 1 

LISTENING-AT-LEVEL 2 PROCESS 1 
<ERRET T>$ 

••BREAK** 

.X » 2 

LISTENING-AT-LEVEL 2 PROCESS 1 
<ERRET T>$ 

••BREAK** 

.X * 0 

LISTENING-AT-LEVEL 2 PROCESS 1 
<ERRET T>$ 

••BREAK** 

.X * 1 

LISTENING-AT-LEVEL 2 PROCESS 1 
<ERRET T>$ 

2 


3. 2.3. 4. Conditional Breakpoints 

Wc continue from the previous example and demonstrate conditional breakpoints with the following: 

1. Enter EDIT and kill the breakpoint from the previous example. 

2. Position the cursor and insert a conditional breakpoint with a predicate of <0? . X>. 

3. Leave EDIT and run the FUNCTION again for the value 10. 

4. Enter EDIT and remove the breakpoint 


The MDL Editor 


32 



The MIDI. Programming Hnvironment 


35 


<EDIT>$ 

$ 

//FUNCTION ((X) I f<&>) 

KBSS 

//FUNCTION ((X) I <&>) 

BK <0? .X> <TIME>$Q$T 
<FIB 10>$ 

••BREAK** 

<TIME> = 14.794538 
LISTENING-AT-LEVEL 2 PROCESS 1 
.XS 
0 

<ERRET T>$ 

••BREAK** 

<TIME> = 15.252382 
LISTENING-AT-LEVEL 2 PROCESS 1 
.X$ 

0 

<ERRET T>$ 

••BREAK** 

<TIME> = 15.716037 
LISTENING-AT-LEVEL 2 PROCESS 1 


and so on. F.vcntually we reach the last breakpoint, and re-enter EDIT 

<EDIT>$ 

$ 

//FUNCTION ((X) I f<&>) 

KB$Q$T 
<ERRET T>$ 

55 


3.2 


The MDL liditor 



36 


'Hie Ml 31. Programming Knvironmcnt 


3.2.4. 

Edit Command Summary 

NAME 

AKGS 

meaning 

? 

none 

type out short summary 

?? 

none 

type out this summary 

0 

anv 

Open object or the value of an atom 

OT 

none 

Open object at the cursor 

Q 

none 

Quit and return to Mdl 

OR 

fix 

Quit and Retry frame 

V 

none 

toggle Verbosity 


Movement commands 


L 

fix 

move I .eft fix objects 

R 

fix 

move Right fix objects 

U 

fix 

move Up fix levels 

D 

none 

move Down one level 

B 

none 

move to Hack of object 

F 

none 

move to Front of object 

UR 

fix 

move Up fix objects and to the Right 

DL 

fix 

move Down fix objects and to the Left 

UT 

none 

Up Top -- go to the place you were after you did 0 

Editing commands 


I 

any... 

Insert arguments to the right of cursor 

I: 

typefix 

make next n objects into a type 

I* 

atom, object 

Imbed command: replace all occurrences of atom (default *) 
in object with objects to right of cursor 

16 

any... 

Insert into group 

SU 

nm.oM 

Substitute new for old 

X 

atom 

set die atom to the object to right of cursor 

6 

any... 

Get E VAL of arguments, insert to right of cursor 

SW 

. none 

SWap the two objects to the right of cursor 

C 

gay 

Change the next object toarg 

C: 


Change the type of the next object to type 

K 

fix 

Kill (delete) the next fix objects 

K: 

none 

Kill (remove) the ‘brackets’ around the next object 

Search Commands 

• 

S/SR 

anv 

Search (Right) until match (=?) is found for any 

SL 

any 

Search Left as above 

Macro Commands 


The MDL Editor 

3.2 



ITic M 1)1. Programming Knvironment ' 


37 


M 

suing 

execute the string as if typed to EDIT 

IT /DO 

fix.strine 

ITcratc the execute string fix times 

Printing commands 


P 

none 

PPRINT the next object 

PU 

none 

PPRINT the next Upper level 

PT 

none 

PPRINT the whole object open 

Cursor commands 


UC 

none 

Use Cursors 

CU 

atom 

set atom to CUrrent cursor position 

GO 

mm 

GO to the specified cursor position 

PC 

none 

Print Cursor positions in the current object 

PA 

none 

Print All cursor positions in the top-level object 

KC 

atom 

Kill the Cursor assigned to the atom 

Debugging 

commands 


BK 

pred,any... 

set BreaKpoint at next object; if pra/evaluates to FALSE, 
don’t break; rest of arguments arc printed out at break 

BA 

pred,any... 

set Breakpoint After next object 

KB 

none 

Kill all Breakpoints in open object 

KT 

none 

Kill 'lliis breakpoint in the object to the right of cursor 

Monitor commands 


UM 

none 

Use Monitors 

RW 

atom.Dred.anv... 

set Read-Write monitor on atom 

RM 

atom.Dred.anv... 

set Read Monitor on atom 

WM 

atom.Dred.anv... 

set Write Monitor on atom 


tF and tS return you to EDIT from a higher level. 

The ATOM * may be used as a fix argument whose value is the largest legal value for that command. 


3.3. Debugging and the Interpreter 

Before continuing the discussion of the various packages that arc used in the debugging of Mm, code, we 
will expand on the discussion of ERROR, FRAME, (and so on) in Chapter 16 of [3]. To summarize that chapter, 
whenever an ATOM is bound or a FUNCTION or RSUBR is MCALLcd in Mol, information is added to the 
contol stack. This information, normally ‘invisible’, may be examined using the functions described in a 
previous section (FRAMES, FR&, FRLVAL, etc.). An invocation of ERROR puts Mdl into a LISTEN-like loop. 

The MDL Editor 


3.2 



38 


The Ml)l. Programming Hnvironment 


Successive ERRORS stack up and arc reflected in the LISTENING-AT-LEVEL message printed whenever 
ERROR or LISTEN iscalled. 

In addition to being examined, the stack may be modified as part of the debugging procedure. For 
example, die SUBRs SET and LVAL take an optional second argument which may be (among several possible 
TYPES) a FRAME. EVALing 

<SET X 10 <FRM n» 

would change the LVAL of X in the nearest binding lower in the stack than die FRAME n FRAMES lower than 
the most recent call to ERROR or LISTEN. Similarly 
CLVAL X <FRM n» 
examines the LVAL in a particular FRAME. 

The most common use of die Mm. interpreter in debugging is to invoke the SUBR ERRET. Widi no 
arguments, it drops all the way to the bottom of the stack and dien calls LISTEN: It says ‘I give up’ (although 
side effects arc not undone). More commonly, ERRET is given a single argument, which causes the last 
invocation of ERROR or LISTEN to return that argument. For example, suppose a program contains , F00 
but FOO has no GVAL. Mill, would respond 
•ERROR* 

UNASSIGNED- VARIABLE 

FOO 

GVAL 

LISTENING-AT-LEVEL 2 PROCESS 1 

You could give up, saying <ERRET>, but it is often more reasonable to say ‘Oh, yes, FOO was supposed to be 

1000', and then 

<ERRET 1000> 

Still better is 

<ERRET <SETG FOO 1000» 
which will prevent future ERRORS from the same cause. 

Finally. ERRET may be given a second argument of a FRAME, which means to return the first argument as 
die value of the invocation of that FRAME. In the previous example, the programmer might look at the stack 
(with F R& or FRAMES) and see 


Debugging and the Interpreter 


3.3 



The M 1)1. Programming Rnvironment 


39 


1 

GVAL 

[FOO] 

2 

EVAL 

[ , FOO] 

3 

EVAL 

[<+ .X .Y , FOO] 

4 

EVAL 

[ < LOSE R .A .6>] 

5 

EVAL 

[</ .GOOD-GVAL <L0SER .A .B»] 

6 

EVAL 

[<WINNER 1.0 2 . 0>] 

7 

LISTEN 

□ 


After some thought, he may just say ‘Well, LOSER apparently needs some debugging, but for now I’m 
interested in WINNER', in which ease he can ‘fake’ a reasonable return from LOSER by typing 
<ERRET 342.0 <FRM 4» 

which returns 342 . 0 exactly as though LOSER had returned it 


More complex errors arc sometimes more difficult to fix, requiring the use of EDIT (at least). In the above 
example, the programmer might decide to debug LOSER after all. ITiere arc two ways to go about this: First, 
if the problem is localized, the FRAME itself may be edited (which is to say, the contents of the FRAME may be 
edited). Changes will show up in the FUNCTION from which the FRAME'S contents were derived. The newly 
corrected FRAME may then be RETRYed. For example, 

<EDIT 3>S 

... various editing commands 

QRS 


Second, the function itself may be edited. In die process, it may be so changed that die FORM which 
caused the ERROR no longer even exists. Often, the easiest solution is to retry the invocation of the EDITed 
FUNCTION from scratch: inthiscase 
<RETRY <FRM 4>>$ 

As always, die major restriction to remember is diat side-effects arc not undone by RETRY. 


3.4. Loading and Dumping 

GROUP-LOAD and GROUP-DUMP arc used to load and dump files of M 1)1. programs in such a way that the 
contents of the file are made available in a Ml)l. structure called a group. Many odicr PACKAGES in die Mdl 
environment operate on or change groups: Among them arc "EDIT", "GLUE", "PDUMP", and the Mdl 
compiler. 

GROUP-LOAD and GROUP-DUMP arc almost as widely used as FLOAD as a way of dealing with groups of 
Mdl functions. Consequently, dicy arc already loaded in most initial Mnt.s, as part of the package 
"GRLOAD". 


3.3 


Debugging and the Interpreter 



40 


'I Tic Ml)l. Programming Environment 


<G ROUP- LOAD file-name:stritw 

group- name:atom> 

file- name: string is the file to load 

group- name:atom is the name to give the group. It is optional and by default die ATOM formed by PARSE of 
the first name of the file to load. ITic group will be stored as the LVAL of group-name. 

GROUP-DUMP is the opposite of GROUP-LOAD. It outputs the group from the Mm. to the file given as its 

first argument Functions unchanged since the last GROUP -LOAD arc copied from the original input file. 

Functions that have been edited arc output using the routine given as the third argument to GROUP-DUMP. 

<GR0UP-DUMP file- naine:st rine 
group- name:atom 

print-routine 

kill-breakpoints?? 

file- name: string is the only required argument. It is the file to which to output the group. 

group->uvne:atoin is optional, and defaults as it docs for GROUP-LOAD, but of course gives an ERROR if the 
group doesn’t already exist. 

print-routine is optional, and defaults to . PPRINT unless the group contained NBIN formal RSUBRs, in which 
case , PR INC is used. 

kill-breakpoints? is optional, by default T, in which case GROUP-DUMP kills all EDIT breakpoints and 
monitors in objects being dumped. Giving a fourth argument of a FALSE to GROUP-DUMP prevents this. 

On die surface, it appears that little happens in the process of loading a file and making it into a group. 

However, a great deal of information about the group has been stored away in associations for later use. 

Some of this information is of use to the Mdl programmer: 

1. On an association between group-name and the ATOM CHANNEL is stored a L 1ST giving the name 
of the file that was GROUP-LOADcd to form the group. Removing this association before 
GROUP-DUMPing has the effect of making the entire group be output from core rather than 
copied from the original source. 

2. On an association between group- name and die ATOM MAGIC-RSUBR the ATOM T is stored if the 
group contained any RSUBRs in fast (NBIN) format It is this association which is used to 
determine the default print-routine in GROUP-DUMP. 

3. The OBLIST path in effect at any time during the load is available. The original path is stored on 
an association between group- name and the ATOM BLOCK. Within the group, the path changes arc 
stored in an association between the group RESTcd to the point of change and the ATOM BLOCK. 

4. If the second clement of a FUNCTION definition is not an ATOM, the actual FUNCTION name 
gotten by EVAL of that clement is stored as an association between the original clement and the 


Loading and Dumping 


3.4 



The M 1)1. Programming Hnvironment 


41 


ATOM VALUE. 

5. The location of a function within the input file is stored as a LIST of the starting and ending 
offsets (in characters) of die function, under an association between a locative to the GVAL of the 
FUNCTION name and die indicator DEFINE. This association is removed by EDIT (and other 
editors) to indicate dial the FUNCTION has been changed. 

There arc additionally several switches that affect the operation of GROUP-LOAD: 

.KEEP-FIXUPS 

If die LVAL of KEEP-FIXUPS is true (and GROUP-LOAD binds it that way during loading), the fixups of 
RSUBRs GROUP-LOADed will be kept. 

. EXPFLOAD 

If die LVAL of EXPFLOAD is true, FLOADs will be expanded. That is, the objects in die file FLOADed will be 
added to die group in place of the FLOAD. The initial setting of EXPFLOAD is a FALSE. 

.EXPSPLICE 

If the LVAL of EXPSPLICE is true, any objects returned within SPLICEs will be inserted directly into the 
group as described above. Hie initial setting of EXPSPLICE isa FALSE. 

3.5. The One-step Debugger 

flic Ml)l. One-step debugger allows the user to step dirough the evaluation of any Mdi expression one 
‘operation’ at a time. Between steps, variables may be examined or changed, functions edited, and so on. 
Tliis is possible because the debugger runs in a different Mm. PROCESS than the expression being stepped, 
and a Mdi. PROCESS may 1STEP another [3]. To load the Debugger. <USE "DEBUGR">. 

The Mdi. Debugger can be in any of three states. In the initial state, OFF, no one-stepping occurs and die 
Debugger docs not listen for any special interrupt characters. T he Debugger is, therefore, completely inactive. 
By typing <DEBUG> to Mdi., you leave the OFF state and enter the READY state. In the READY state no 
one-stepping occurs, however the Debugger docs listen for interrupt characters. By typing the interrupt 
character tB, you enter the ON state and one-stepping begins. In addition, if you were stopped at an EDIT 
breakpoint when the tB was typed, the breakpoint will automatically be exited and evaluation continued in 
die one-stepping state. 

While in the ON state, the Debugger will proceed through the execution of any Mdi. objects one step at a 
time. In essence, the Debugger stops just before and just after every call to EVAL. At each step the Debugger 
will indicate its current condition as follows. If EVAL is recursively entered at level, n, with input, object , the 
display will be: 


3.4 


Loading and Dumping 



42 


The Ml)l. Programming Knvironment 


n= > object 

(where object is ampersand printed). If EVAL is returning from level, n, with result, object , the display will be: 
n< - object 

(where object is ampersand printed). 

The Debugger will stop at each such step and wait for directions. , ITicrc arc four interrupt characters that 
may be typed to proceed further in the program: tN, tO, tR and tA. They each take an optional prefix 
argument that serves as a repeat count 

tN 

causes the Debugger to perform the next step of the current evaluation. 

to 

causes the current object to be completely evaluated without any one-stepping and then stops with the result 
of that evaluation. tO is useful for stepping over COND predicates that you know will not succeed, or more 

generally, uninteresting parts of a program. 

tA 

is similar to tO, but specific to the evaluation of the argument list of a FUNCTION, PROG, or REPEAT. Typing 
tA during such evaluation allows the rest of the argument list to be evaluated without one-stepping and then 
slops before evaluating the body of a FUNCTION, PROG, or REPEAT or returning of a result. 

tR 

is most effectively used in a REPEAT or PROG loop. Typing tR causes evaluation to proceed until control 
returns to the point in the body of the REPEAT/PROG at which tR was typed. It thus allows you to go once 
around a loop. _ 

It should be noticed that, when stopped at one of these steps, you can examine and modify program 
variables, do a FRAMES or FR&, EDIT FUNCTIONS and set breakpoints, and in general perform any valid 
Mdl operations. Also, when you stop, die LVAL of the ATOM LAST-OUT will be set to the object the 
Debugger last typed out. This is useful if the & performed by the Debugger did not show a particular detail 
that you are interested in. 

Use the interrupt character tE to leave the ON state and return to the READY state. Use the interrupt 
character tQ to leave either the ON state or the READY state and return to the OFF state. When leaving the ON 
slate as described, the execution currently being onc-stcppcd will be finished in the usual manner. 

The function REPAIR attempts to fix any errors in the Debugger that you might happen to invoke. These 
errors arc easily distinguished since they never occur in Mdl’s MAIN PROCESS. Therefore, you will see: 


The One-step Debugger 


3.5 



The Ml)l. Programming Environment ' 


43 


LISTENING-AT-LEVEL //» PROCESS n 

(where n is not 1). REPAIR turns off the Debugger and returns you to running in the MAIN PROCESS (no 
longer one-stepping). Because REPAIR turns off the Debugger, you. must do <DEBUG> again if you wish to 
try any further one-stepping. 

3.5.1 . MDL Debugger Command Summary 

<USE "DEBUGR"> loads the Debugger. 

<DEBUG> makes the Debugger ready. 

tB begins one-stepping. 

t N performs the next step of the computation. 

tO steps completely over the next computation, then stops and continues one-stepping, 
t A evaluates the arguments of the current object then stops and continues one-stepping through the body, 
t R continues evaluation until you return to this point. 
tE ends one-stepping. 

tQ quits one-stepping and makes the Debugger unready (turned off). 

<HELP>printsa command summary. 

< RE PA I R> attempts to repair any Debugger errors you might invoke. 


3.5.2. MDL Debugger Special Features 

The following flags have special importance to the Debugger: 

.INOENT-INC 

is the amount by which to indent for each level (by default 2 spaces). 

.INOENT-MOD 

The indentation-level is the real level taken modulo this number. The default is 10. Indentation ‘restarts’ 
when level gets here. If you don’t like this feature, make the number large. 

, INDENT-DIF 

is the minimum amount of free space to reserve on each line that indentation must not touch (by default 20). 
Therefore at level L the indentation is exactly: 


3.5 


The One-step Debugger 



44 


The M 1)1. Programming Environment 


<MIN <• .INDENT-INC <M0D .L , INDENT-MOD» 

<- <13 , 0UTCHAN> , INDENT-DIF» 

.OUT-FAST 

if true tlic Debugger will not stop when leaving a level with a result. The default is T. 

.OUT-UNIQUE 

if both this and previous flag arc true successive ‘outs’ of the same item will not be displayed (defaults to T). 
.SELF-FAST 

if true the Debugger will not stop when entering a level with an object which EVALs to itself (c.g. ATOMS, 
FIXes, STRINGs). The default is T. The display will be: 
n: object 
.FORM-FAST 

if true the Debugger will not stop when entering a level with any of the ‘short’ FORMS (e.g. <>, . F00, , BAR, 
'ANYTHING). The default is T. Hie display will be: 
n : .FOO = Ival 

Any of these flags can be SETGed by you to tailor the Debugger to your own tastes. 

3.6. Execution Tracing 

The "TRACE" PACKAGE provides a facility for observing the arguments and returned values of selected 
FUNCTIONS and RSUBRs. It is possible to print the arguments on entry to the function, print the value 
returned, and to break on entry to and exit from the function. All actions may be performed conditionally. 
To load TRACE, type 

<USE "TRACE"> 

3.6.1. Using TRACE 

TRACE is invoked by 

<TRACE what options > 

what is either an ATOM or a LIST of ATOMs, naming the things to be traced. These may include SUBRs, 
FUNCTIONS, and RSUBRs; however, anything which is traced must EVAL all of its arguments, options 
specifics the behavior of TRACE with respect to the specified function. There arc five switches, as follows: 

IN-BREAK 

means break (cause a Ml)I. E RROR) before calling the function. Normally oflf. 


The One-step Debugger 


3.5 



The Ml)l. Programming Knvironment 


45 


IN-PRINT 

means & function arguments on entry. Normally on. 

OUT-PRINT 

means & function value on exit. Normally on. 

OUT-BREAK 

break after executing the function call. Normally off. 

VERBOSE 

means & die arguments to the function one per line. ITiis is useful if the arguments arc long. Normally off. 

To cause a given option to be unconditionally on, include its name (an ATOM) in the options TUPLE. To 
cause an option to be unconditionally off, include a two-element LIST, composed of the option name and a 
FALSE. If the second element of the LIST is neither FALSE nor an ATOM, it will be EVALed each time 
TRACE examines the setting of the given option for the function. This allows conditional breakpoints, for 
example. 

Thus: 

CTRACE F00 (OUT-PRINT <>)> 

will cause FOO’s arguments to be printed on entry, but the value will not be printed. 

< TRACE F00 (OUT-PRINT '<G? <TIME> 4.0>)> 
will cause printing of the value after four seconds of epu time have been used. Printing of the arguments will 
occur each time F00 is called. 

UNTRACE turns off tracing of the specified functions: 

< UNTRACE what: atom- oHisO 

What defaults to a L 1ST of all functions which have been traced. 

3.6.2. Understanding TRACE 

TRACE works by CHTYPEing die specified functions to new types which have an APPLYTYPE associated 
with them. This means that one cannot trace calls to RSUBRs or RSUBR-ENTRYs which arc already linked. 
In addition, it means that UNTRACE must be used to get the old value back. To determine the status of a 
function with respect to tracing, say 
<GET applicable TRACE> 

This returns FALSE if applicable is not traced; otherwise, it returns an object which describes the settings of 
die various options. The object has a PRINTTYPE which associates the name of each option with its setting: 


3.6 


Execution 'fracing 



46 


Ihc Ml)l. Programming Knvironmcnt 


<GET , F00 TRACE>$ 

F00 

IN-BREAK: #FALSE () 

IN-PRINT: T 

OUT-PRINT: <G? <TIME> 4.0> 

OUT-BREAK: #FALSE () 

VERBOSE: #FALSE () 

Individual settings for a particular function may be changed by PUT ting into this structure: 

<PUT <GET , FOO TRACE> .IN-BREAK T> 
causes a break whenever FOO is called. 


3.7. Monitors 

A common problem in debugging is the mysterious 'clobbering' of some value or element of a data 
structure. Mm has imbedded in it a mechanism for triggering interrupts on references, either for reading or 
writing, to values of variables and elements of structures. 

The "MONITOR" PACKAGE is designed to be a readily accessible user interface to these "READ" and 
"WRITE" interrupts in the Mm. interpreter. 

To obtain "MONITOR", 

<USE "MON I TOR" > 

There arc three basic kinds of ‘things’ which can be monitored: values of ATOMs, elements of 
STRUCTUREDs(thc TYPE of the element is not important), and ASSOCIATIONS. 

For ATOMs, the LVAL or the GVAL may be monitored. If the LVAL is to be monitored, tne ATOM must be 
ASSIGNED?. For the GVAL, the ATOM must be GBOUND?. If these conditions cannot be met, a monitor 
cannot be generated. 

For STRUCTUREDs, the monitor is on the //th element, where n is specified when the monitor is created. 
Remember, the monitor is on a slot of the STRUCTURED, not on the contents of that slot! 

For ASSOC IAT IONs, the monitor is on the association itself. 

3.7.1. Monitor Internals 

This section expands on the discussion of monitors in the Mdl document itself [3]. 

Mdi. defines two types of monitors: Read and Write. These arc implemented in the language by two 


Fjtccution Tracing 


3.6 



The MIDI. Programming Bnvironment 


47 


intemipts, READ! -INTERRUPTS and WRITE ! -INTERRUPTS, respectively. In addition, the "MONITOR" 
PACKAGE can allow read-write monitors. The "MONITOR" PACKAGE is at base a set of functions to create 
and handle these interrupts. A monitor is triggered in the following cases: 

Read monitor: 

For LVALs -- via LVAL 

For GVALs - via GVAL 

For STRUCTUREDs - via NTH 

For ASSOCIAT IONs -- via GET and GETPROP 

Write monitor: 

For LVALs -- via SET or "AUX" bindings 
For GVALs - viaSETG 
For STRUCTUREDs -- via PUT, SUBSTRUC 
For ASSOC I AT IONs -- via PUT andPUTPROP 

Note that PUTRESTs of LISTs which may alter the nth element of a LIST, do not access the old nth 
element of the LIST and therefore do not cause a write monitor to trigger. 

Internally, Mol performs monitoring on LOCATIVES to STRUCTUREDs. In facL LVAL and GVAL are 
really pointers to an internal structure. This need not concern the user except in the ease of LVALs of ATOMS. 
In this ease. Mot will monitor a LOCATIVE to that (exactly that unique) binding of the ATOM. When that 
binding becomes invalid, or more precisely, 

<N0T <LEGAL? locative» 

a function in the "MONITOR" PACKAGE will make the monitor vanish. Illegal monitors print as 
^MONITOR [ILLEGAL] (if you ever get a pointer to one). Remember that if you want to monitor the LVAL 
of an ATOM bound in a FUNCTION (or PROG, etc.), you must create a new monitor each time, as a new 
binding is created each time. One way to do this is to edit into the FUNCT ION a call to MONITOR (see below) 
after the ATOM becomes ASSIGNED?. Fortunately, KDIT (see section 3.2.2.9) has commands to do exactly 
that 


3.7.2. Creating MONITORS 

Creation of all monitors is done through a call to MONITOR (which returns an object of TYPE MONITOR), 
as follows: 


3.7 


Monitors 



48 


The MI)L Programming Hnvironment 


<M0NIT0R tvpetstrinf 
object 
where 
predicate 
todo.tuple > 

where: 

type is one of "READ", "WRITE", or "RW". 

object is either an ATOM or a STRUCTURED, or an ASSOCIATION item. 

where is either LVAL or GVAL (if object is an ATOM) or a FIX, (if object is a STRUCTURED), or an 

ASSOCIATION INDICATOR. 

predicate is something which is EVALed to determine whether the monitor is to be triggered; this defaults to 

T. ITie "MONITOR" PACKAGE defines three variables which can be referenced in the test: 

OLDVAL is the old value of the object monitored. 

NEWVAL is the new value of the object monitored. 

MONOBJ is the object monitored (ATOM or STRUCTURED). 

Here value means LVAL, GVAL, or element Obviously, NEWVAL is not set for "READ" monitors. 

lodo is any number of things to be EVALed and PRINTcd when the monitor is triggered. 

Note that predicate and lodo are identical to the analogous arguments of the ED I T BK command. 


3.7.3. Monitor Events 

When a monitor is triggered, the following is printed (remember the predicate is evaluated before this), 
and then LISTEN is called. Tocontinue, <ERRET T>. 

Read: 

••READ of where of object •• 

Value: oldval 
todol = result! 
todo2 = resull2 


Write: 


Monitors 


3.7 



The M 1)1. Programming Hnvironmcnt ' 49 

♦•WRITE of where of object ** 

Old value: oldval 
New value: newval 
todol - result I 
todo2 = result! 

A slightly different first line format is used for associations. 

3.7.4. Killing Monitors 

Killing a MONITOR is accomplished by calling KILL-MONITOR as follows: 

<KILL-M0NIT0R monitor y 
or 

<KILL-M0NIT0R tvne object wfj£££> 

In the latter case, type , object , and where arc as given in the original call to MON I TOR. 

To kill all MONITORS, use 
<K ILL -ALL -MONITORS) . 

3.7.5. Other Monitor Routines 

<M0N0BJ monitor^ 
returns the object monitored. 

<M0NSPEC monitor > 
returns the whereof the MONITOR. 

<CLEAN-MONITORS> 

flushes invalid MONITORS from the MONITOR LIST. This is done internally and need not be called 
routinely. 

.MONITORS 

is a LIST of all current MONITORS. 

3.7.6. What You Can’t Do with Monitors 

You can’t monitor the LVAL of something BOUND? but not ASSIGNED?. B.g., 


3.7 


Monitors 



50 


ITic M 1)1. Programming Knvironmcnt 


<DEFINE WRONG ("AUX" BAR) 

<MONITOR "READ" BAR LVAL> 


You can’t expect compiled code to cause monitors to be triggered. Naturally, you can’t place monitors in 
compiled code; however, a compiled reference to a monitored ATOM will not usually cause the monitor to 
trigger either. 


3.8. FINDATOM 

Hie "FINDATOM" PACKAGE is intended to reduce the problems caused by multiple OBLISTs and 
lengthy ATOM names in Mdi.. It allows one to find all ATOMs whose PNAMEs match some specification, which 
need not be exact: in addition, one may place constraints on the values of die ATOMs found. 

F I NDATOM is invoked as: 

<FINDAT0M snrcslr: slrin f 

searchlist 

constraints 

outobhlisO 

spccstr is a STRING describing the PNAMEs of the ATOMs one wishes to find. Three special characters are 
recognized in this STRING: 

*: matches anything, including an empty string 

=: matches any single character 

tQ: quotes the following character 

Search strings may be an arbitrary concatenation of normal and special characters. For example: 
"*S0M*": matches any ATOM containing "SDM" anywhere in its PNAME. 

"*=SDM*": matches any ATOM containing "SDM" in its PNAME, provided that at least one character 
precedes the "SDM". 

"tQ*": matches any ATOM with PNAME "•". 

"*": matches any ATOM. 

If tQ is the only special character in the string, it need not be quoted: "tQ" searches for ATOMs with 
PNAME "tQ". 

searchlist specifies the OBL ISTs to search. Possible values arc: 

#FALSE (): search all OBLISTs in .OBL 1ST 


Monitors 


3.7 



The Ml)l. Programming Hnvironment 


51 


0FALSE ( oblists-or-forms): scarchallbulthcOBLISTsspccificd. 
oblist: search only this OBL 1ST. - 

lisi-uf-oblistsr. search only the OBL I STs in this list 
else : search all OBL I STs. This is the default 

constraints is a TUPLE describing the value of each AT OM found. It may consist of any number of valid TYPE 
names, along with arbitrary structures and the following special objects: 

T: if present overrides any other constraints; if no other constraints arc specified, this is assumed. Any 
AT OM matching specstr will be accepted. 

ANY: overrides any constraint other than T. Any ATOM matching specstr which has a value (either GVAL 
or L VAL ) will be accepted. 

<>: any ATOM which has no value will be accepted. Note that giving both ANY and <> is equivalent to 
giving T. 

LINK: any LINK will be accepted. 

If other constraints arc provided, they work as follows: all valid TYPE names given (ones for whom 
VALID-TYPE? returns T) arc stored in a structure; when a value is encountered, its TYPE is MEMQed 
on this structure. If the ATOM docs not succeed here, it is next checked against the ‘arbitrary 
structures.’ 

Anything in constraints which is neither one of the above ‘special objects’ nor a valid type is treated as a 
DECL specification. All such objects arc put in a FORM starting with OR, which has the effect of 
generating a single DECL specification. When a value is found, DECL? is called with the value as its 
first argument and the generated FORM as its second. If DECL? returns T, meaning that the FORM is 
valid as a DECL for the VALUE, the ATOM is accepted. 

Examples: 

ATOM FALSE ’<LIST [REST FIX]> 

specifics that any ATOM accepted must have either a GVAL or an LVAL which is of type ATOM or 
FALSE, or which is a LIST of FIXes. 

' <0R ATOM FALSE> 'CLIST [REST OBLIST]> 
specifics that any AT OM accepted must match the DECL 

COR COR ATOM FALSE> CLIST [REST OBLIST]>> 

outobl, if present, is a LIST of OBL I STs which is the LVALofOBLIST when F I NDATOM prints tilings. Thus, 
one may force all ATOMs to be printed with lull trailers by providing an empty LIST here. The last 
argument given to F I NDATOM, provided it is a L 1ST, is assumed to be outobl. 

FINDATOM prints the name of each ATOM it accepts, followed by the STRING "Gassigned" and the 
type of GVAL if the ATOM has one; this will be followed by the STRING "Assigned" and the type of the 


3.8 


FINDATOM 



52 


The MDI. Programming Hnvironment 


LVAL if the ATOM has one. It prints the number of ATOMS found when it finishes. 

3.9. "PINFO" 

"PINFO" is an informational PACKAGE. It is used to examine the OBLISTs of die PACKAGES loaded into 

an Mdi.. There arc two major entries in PINFO. 

<PCK-INFO package: siring 

internal?:booleari> 

Both arguments to PCK- INFO arc optional. If neither argument is given, the names of the PACKAGES loaded 
into the Mot. arc listed. If a package is given, the contents of the package’s ENTRY OBL I ST arc listed, as well 
as information about the VALUE of each ENTRY. If internal? is provided and non-FALSE the contents of the 
internal OB LIST arc also listed. PCK -INFO prints an error message if package is not loaded. 

<PCK-USES package:siring> 

lists the names of PACKAGES USEd by package or returns a FALSE if package is not loaded. 

3.10. Debugging in a Run-time Environment 

A fairly common occurrence when running ‘debugged’ code is to find that if was not after all completely 
debugged. It is useful to be able to load interpreted versions of some FUNCTIONS in a PACKAGE into the 
compiled environment for debugging. "DFL", "RDFL", and "UNLINK" arc PACKAGES written to simplify 
this procedure. 

3.10.1. DFL 

The "DFL" (‘Debugging Fload’) PACKAGE is a set of routines for loading and dumping of small numbers 
of FUNCT IONs from a larger file. It is useful in debugging already running systems, or ones which have not 
been GROUP-LOADed. To get "DFL" 

<USE "DFL"> 

The main entry of the "DFL" PACKAGE is DFL: 

<DFL func- names file-name:string unlink?: booleari> 
where all arguments arc optional and 

June- names is the namc(s)of the DEFINEd FUNCT ION(s) to be obtained from this file. It may bean ATOM, a 
STRING, or a structure of ATOMs or STRINGS; if ATOMS arc given, their SPNAMEsarc used. The default is 
the argument last given to DFL or RDFL. 

file-name is the file to obtain the FUNCT ION(s) from. 'Ihc default is the last file DF Led or RDF Led. An ATOM 
may be given, in which ease its SPNAME is used for the first file name. 

unlink? If this is true, and if one or more of the values replaced by the DF Led FUNCT IONs were RSUBRs or 


FINDATOM 


18 



Ihc MDI. Programming Hnvironmcnt 


53 


RSUBR-ENTRYs, the reference VECTORS of all RSUBRs, including pure ones, will be searched for 
occurrences of the old value; such occurrences will be replaced by the ATOM. r I1iis is the inverse of 
RSUBR-LINKing. Pure structures will be unpurified; this docs not change their address in core, but 
simply makes the page they live in rcad/write. 

In the normal ease, if an RSUBR or RSUBR-ENTRY is being replaced, unlinking will occur automatically in 
garbage-collector space only if RSUBR-LINK is T. Also, remember that unlinking is not the same as 
substituting: only RSUBRs stored at top level in reference VECTORS arc found; if the old value itself was in a 
structure (such as a dispatch table), it will not be replaced. 


3.10.2. RDFL 

RDFL is similar to DEL but is for reloading RSUBRs rather than FUNCTIONS. RDFL is contained in the 
PACKAGE "RDFL". 

<RDFL June- names file-name unlink? glue?> 

The first three arguments are as for DFL. The only difference between RDFL and DFL (barring the effect of 
the fourth argument) is that RDFL searches in the file for <SETG ’ rather than ‘<DEFINE ’. 

glue? If non-FALSE, RDFL will READ and EVAL the next object in the file following each RSUBR read. This 
will in the nonnal ease obtain the ‘glue bits’ for the RSUBR (see section 6.1 ). The default for glue? is 

<AND ASSIGNED? GLUE!- > .GLUE!- > 

'ITiis is the FORM used in NB IN files to determine whether glue bits should be kept. 

Note that RDFL will work to reload any SETGed object not just RSUBRs. 

RDFLing an RSUBR-ENTRY docs not work and may well be fatal: you must RDFL the RSUBR in which 
the RSUBR-ENTRY is an entry, as well. 

3.10.3. UN-DFL 

UN-DFL is for writing out DF Led FUNCTIONS after EDITing. 

<UN-DFL aloms filnam force?? 

atoms is an ATOM or a list of ATOMS, which will be UN-DF Led. The FUNCTIONS defined must all be from the 
same file, or UN-DFL will not work. UN-DFL can only UN-DFL things which were previously loaded by 
DFL. 

filnam The default is the file the ATOMs originally came from. 

force? Normally, UN-DFL will object if there is a version between the file the FUNCTIONS came from and the 
file which UN-DFL will create: it thinks it will likely destroy useful information. Providing an ATOM here 
causes this scruple to be ignored. It is almost always unwise to do so. For example: 


3.10 


Debugging in a Run-time Knvironment 



54 


The M 1)1. Programming Environment 


<DFL (F00 BAR)> <UN-DFL F00> <UN-DFL BAR> 
will cause UN-DF L to fail. Moral: DFL and UM-DFL your FUNCTIONS together. 

3.10.4. UNLINK 

The "UNLINK” PACKAGE contains three entries: UNLINK, PURE?, and UNPURIFY. UNLINK is 
sometimes called by DFL; PURE? and UNPURIFY arc good ways to l&urativcly defeat the safety ‘interlock’ of 
Mdu 

UNLINK is used to unlink RSUBRs after they have been linked. (See the discussion of RSUBR-L INK in 

[3]). 

CUNLINK alums pure7> 

alums is a list of the ATOMs to be unlinked, or a FALSE, meaning unlink every RSUBR in the Mill,, or a 
group-name, meaning unlink calls to all FUNCTIONS and RSUBRs in the group. 

pure? is optional and defaults to FALSE, but if true, even pure RSUBRs will be searched. UNLINK 
examines all the OBLISTsin the Mol, looking for RSUBRs; if an RSUBR exists only in a structure, and not at 
top level in any RSUBR's reference VECTOR, it will not be found. 

CUNPURIFY Dure-obieet:anv > 

PURE? takes an object and determines if the right half of the value word is greater than the number 
contained in the Mdl location PURBOT, which is the lowest pure location in MOL. Ergo, ‘Is the object I gave 
you pure?’ It is only meaningful for structures. 

<UNPURIFY Dure-obiect:anv > 

UNPURIFY takes a single argument, which must be of PRIMTYPE VECTOR or UVECTOR (i.e., it must have 
an AOBJN pointer for its value word). It causes the pages in which that object lives to become impure, and 
returns T. 

Because there is no way on ITS to make a read-only page an impure page directly, die following algorithm 
is used by UNPURIFY: 

1. Is the object pure, according to PURE ? If not, leave. 

2. Is UNPURIFY- PAGE ! -IUNLINK GASSIGNED? If not, get a page from the interpreter, and SETG 
the aforementioned ATOM to its number. I.e., the page is more or less permanently taken for use 

ofUNPURIFY. 

3. For each page occupied by the object: a) If die page is already impure, do nothing; b) otherwise. 


Debugging in a Run-time Environment 


3.10 



The M1)L Programming Knvironment 


55 


map the page on top of UNPURIFY-PAGE; c) create a new, impure page where the old page was. 
d) copy the contents ofUNPURIFY-PAGE back to the old, now impure page. 

f 

Thus, no pointers arc changed: as far as Mdi. is concerned, in fact, nothing has changed. 'Hie unpurified 
pages arc still pure, according to its page map. However, you may freely change the unpurified object. 

If your change to the newly unpurified object consists of PUTing a pointer into garbage-collected space 
into the object, you may lose completely unless the pointer points to a frozen object. The Mnt garbage 
collector docs not examine unpurified objects. UNLINK can only use UNPURIFY because all ATOMS 
referenced by pure RSUBRs arc indeed frozen. 

For the above reason, use of UNPUR IF Y is not recommended for the general user. 

3.11. CRITIC 

"CRITIC" is a PACKAGE designed to aid the user in debugging (and perhaps increasing the efficiency of) 
his programs. It accumulates and prints in a readable format information about the interactions of the various 
FUNCT IONs (and LVALs and GVALs) in a group. It also warns die user about various conditions it considers 
to be either non-optimal or erroneous, such as incorrect use of SPECIAL, forgetting to QUOTE some structure, 
and so on. Like most critics, it is sometimes wrong, but it tries to perform a useful service. To load 
"CRITIC" say 

<USE "CRITIC"> 

'There arc two major entries, one of which prints more information than the other. 

<CRITIC SMULMHK 

output-file> 

where group- name is the ATOM returned by a GROUP -LOAD, and the optional output-file is a STRING giving 
the name of the file to output to (by default with second file name "CRITIC"). This can also be a CHANNEL 
if you arc planning to do several CRITICS into one file. CRITIC prints information about interactions 
among the FUNCTIONS in a group (as described below). 

<CRIT IC-NOTES eroun-name 

output-file> 

is similar but only prints ‘errors’ and ‘warnings’ -- things that might be problems with die FUNCT IONs in die 
group. 

'Ihc output fomiat (for each FUNCTION and for die group as a whole) is as follows: 
function ( object number of function in group) 

Call ed-by: a list of all the functions which call function 


3.10 


Debugging in a Run-time Environment 



56 


Ihc Ml)l. Programming Knvironmcnt 


Cal 1 s: a list of all the functions called by function 
S E T G : ex tcrnal globals SET Ged by function 
GVAL: external globals referenced by fuiKlion 
SET: external variables SET by function 
LVAL : external variables referenced by function 
SPECIAL: variables declared SPECIAL by function 
USE -DATUM: DATUMs used by function 

The above table is printed by CRITIC but not by CRITIC-NOTES. ‘Rxlcmaf as used above means 
‘External to function'. 

CRITIC-NOTES and CRITIC both print information about possible defects or errors in each FUNCTION. 
ITicsc can be any or all of the following (explanations follow where needed). 

3.1 1 .1. Global problems with the Group 

FLOAD in file. 

This is pretty minor: FLOADs at top level arc discouraged if you can avoid them. 

BLOCK or ENDBLOCK at top level in PACKAGE. 

PACKAGES should not have to resort to this. 
atom-name : MANIFESJed structure. 

The ATOM given is a structure but was MANIFESTed. Since a MANIFEST is copied within the reference 
VECTOR of any RSUBR that uses it, it is usually not a good idea.. 

ENTRY s not bound, assumed locals: atom-list 

The ATOMS given were made ENTRYs in the PACKAGE, but were not bound, so CRITIC has assumed they 
arc locals, for lack of something better to do. 

Packages USEd but never referenced: package-names 

These PACKAGES were in USE statements but no ATOM was ever found which fell on their OBLISTs. 
'Iltcrc will sometimes be incorrect entries in this list if you USE a PACKAGE which sets up a funny ENTRY 
OBL I ST (RPACKAGEs included) or no OBL ISTs at all. 

Internal functions unused: atom-list 

ITicsc are FUNCTIONS DEFINEd but apparently never referenced and not entries. There will sometimes 
be incorrect entries in this list if you have FUNCTIONS invoked only by funny dispatching methods, such as 


CRITIC 


3.11 



The Mill. Programming Environment 


57 


APPLYing or EVALing an element of a structure. 

Internal globals unused: atom-list r 

ATOMs SETGed at top level but never referenced. 

Internal manifests unused: atom-list 

ATOMs SETGed and MANIFESTed at top level but never referenced. 

3.11.2. Parameter list problems 

ATOM atom-name used twice in parameter list. 

The ATOM named was bound twice in the same parameter LIST within the FUNCTION. Mill, doesn’t 
worry about this, but you might 

Untasteful re-use of ATOM atom-name in ROOT. 

An ATOM was bound which happened to be in the ROOT OBLIST and happened to have a GVAL that is a 
SUBR or F SUBR. Ibis is reported because the ATOM will have to be unpurified, which is expensive. 

"BIND" illegally located. 

A "BIND" was found other than at the beginning of a parameter LIST. 

"CALL"/"ARGS" illegally located. 

A "CALL" or "ARGS" was found after the "AUX" in a parameter LIST. 

"OPTIONAL" illegally located. 

"OPT IONAL" was found after "AUX" in a parameter LIST. 

"TUPLE" illegally located. 

"TUPLE" was found after "AUX" in a parameter LI ST. 
atom "AUX" illegally QUOTEd. 

The ATOM named was given as a quoted argument in the " AUX " part of the parameter LIST. 

External locals set but unbound and unDECLed: atom-list 
External locals set but unbound: atom-list 

Two different classes of hacking an external local. In both eases it means that the ATOMs did not appear to 


3.11 


CRITIC 



58 


Ihc Ml)l. Programming Knvironmcnt 


be improperly SPECIALed, since no one bound them higher in the call tree (or at top level). These are most 
often indications of misspelling or forgetting to put a temporary in the parameter LIST. 

External locals used but unbound and unOECLed: atom-list 

External locals used but unbound: atom-list 

A reference to an external local which was not bound anywhere is probably a misspelling of a SPECIAL 
bound elsewhere or the result of forgetting to put the ATOMS in the FUNCTION’S parameter LIST. 

External locals set but unDECLed: atom-list 

External locals used but unDECLed: atom-list 

An external used but not DECLed usually means that the compiler will produce poorer code. 

3.11.3. Unused ATOMS 

Argument unused: atom-list 

The arguments listed were never referenced. 

Unused: atom-list 

The AT OMs listed were bound at top level of the FUNC T ION and never referenced. 

Unused in PROG: atom-list 

Similar to the above, but the ATOMS were bound within a PROG. 

Unused in REPEAT: atom-list 

Similar to the above, but the ATOMS were bound within a REPEAT. 

Unused in FUNCTION: atom-list 

Similar to the above, but the ATOMS were bound within a nameless FUNCTION, such as the second 
argument to a MAPF/MAPR. 

Unused SPECIALS: atom-list 

The same as above (including ‘ ... in FUNCTION’, etc.), except that the ATOM was SPECIAL. This 
message results from really looking down the call tree, so it is more accurate about this problem than the 
compiler, which only looks at the FUNCTION in which the ATOM is bound. 


CRITIC 


3.11 



Hie M 1)1. Programming Environment 


59 


3.11.4. Function calling errors 

Calls undefined function alom. 

The FUNCTION calls an undefined FUNCTION (undefined at the time CRITIC ran). 

Calls junction with too few arguments. 

Calls junction with too many arguments. 

External FUNCTION function 

'llic FUNCTION named is called but doesn’t scent to fall on any of the OB LISTs associated with the group. 

3.1 1 .5. SPECIAL/UNSPECIAL problems 

SPECIALS never used as SPECIALS: atom-list 

'ITtc ATOMs were made SPEC IAL but never used outside the FUNCTION in which they were hound. 
atom-name is unused or should be SPECIAL. 

A very specific error which means that the ATOM given (always one of INCHAN, OUTCHAN, or OBLIST) 
was bound but never referenced within the FUNCTION, and was not SPECIAL: Either you bound it for 
effect and forgot to SPECIAL it. or you didn’t need to bind it. 

atom unbound in paths: path-list 

If the FUNCTION is called by one of the paths given, the atom will be unbound. A path is just a list of calls 
CRITIC has found arc possible, such as ( F00 BAR BLECH), meaning l F00 is called by BAR which is called 
by BLECH’. 

The ATOM atom used in fail should be special in fcn2. 

'This note will appear with both FUNCT IONs mentioned. It means that atom is referenced in fcnl and the 
nearest FUNCTION that binds it and calls down to fcnl is fcn2. 

3.1 1 .6. DECLing problems 

RSUBR has no DECL. 

FUNCTION has no DECL. 

Parameters not DECLed: atom-list 

The ATOMs given were bound but not DECLed in the parameter list of a FUNCTION, PROG, or REPEAT. 


3.11 


CRITIC 



60 


The Mill. Programming Hnviromnent 


No DECL in DECL for: alom-list 

The AT OMs in the alom-list given had no associated declarations. 

NEWTYPE not DECLed: type-name 

A NEWTYPE of a structured type was made but no DECL argument was included. In a structured 
NEWTYPE. including a DECL of the interior can greatly increase the efficiency of compiled code. 

Illegal DECL: alom-list dec / reason 

The DECL pair given had illegal syntax for the reason given, 'fhese can include: 

"Not a legal type": An object appeared in a DECL thatwasnotan ATOM, FORM. orSEGMENT. 

"Type-name not a type: atom”: Something other than a type-name or special symbol (such as ANY) 
appeared where a type was expected. 'ITiis is sometimes caused by not having your environment 
completely set up when CRIT IC is run. 

"FORM/SEGMENT too short": A FORM/SEGMENT construction of only one element was found. 
"SPECIAL/UNSPECIAL with three or more elements” 

"Bad PRIMTYPE type": The type given in a PR IMTYPE was not a type-name. 

"PRIMTYPE with three or more elements” 

"Bad type of structured type": The type-name given as the type of a structured type was not a 
type. For example, <F00 FIX> where FOO is not atype. 

"Bad BYTES specification": A BYTES specification was not of the form <BYTES fix fix>, or the 
byte si/.c was greater than 36. 

"BYTES DECL too short": A BYTES construction of only one element was encountered. 

"BYTES DECL too long": A BYTES construction of more than three elements was encountered. 
"VECTOR in OR specification": An NTH/REST/OPT construction was found at top level of an OR. 
"Nth/REST/OPT too short": A one-element NTII/REST/OPT. 

"Only REST or OPT may follow OPT": Something other than a REST or OPT was found after an 
OPT. 

t 

"REST must terminate DECL": Something was found after a REST in the DECL. 


CRITIC 


3.11 



The MI)L Programming Hnvironment ‘ 


61 


3.11.7. Miscellaneous 

Possibly should be QUOTEd: structure v 

The structure given will be =? to itself if EVALed. CRITIC lists these under the assumption that you 
might have forgotten to QUOTE a structure that should have been. It says "possibly" because you obviously 
want to build new structure sometimes. One way to do this without offending CRITIC is to build new 
structure with explicit calls to LIST. VECTOR, etc. 

3.12. Program Environments 

The ENV PACKAGE makes it easier to load programs into different environments. It allows certain actions 
to be taken during loading only if a given 'feature' is present. ENV has three ENTRYs, and is prcloadcd. 

< FEATURES features: tuple) 

If given no arguments, FEATURES returns the current feature LIST. If its first argument is not a FALSE, the 
arguments arc added to the feature LIST. If the first argument is FALSE, the remaining arguments are 
removed from the feature LIST. Thus, 

FEATURES "COMPILERS 

says that we are currently in a compiler. All of the 'feature' arguments may be cither STRINGS or ATOMs; 

internally features arc stored as STRINGS to avoid OBLIST problems. 

<FEATURE? features: tuple ) 

returns T if any of its arguments is on the feature LIST. 

<EVAL-WHEN features 

consequences: tuple ) 

uses the first argument to decide whether to evaluate the remaining arguments. 

features specifics which feature! s) to look for. It may be a single feature or a LIST of features. In the latter 
case, if the first clement is a FALSE, what is checked for is the absence of the features listed. Note that this 
argument is often a LIST created out of arguments to FEATURE?. 

consequences arc things to be evaluated only if die features arc present (or absent, in the FALSE case). 

For example, 

<EVAL-WHEN GLUE <SETG F00 1>> 

would perform the SETG only if it’s evaluated in a GLUE (or some other environment defining that feature). 

<EVAL-WHEN (<> COMPILER) <SETG BAR 2>> 
would not perforin the SETG in the compiler environment 

Unfortunately, the ENV PACKAGE is a relatively recent innovation, and so many programs do not set up 
appropriate environments. 


3.11 


CRITIC 



62 


The M 1)1. Programming Environment 


4.0 



ITic M 1)1. Programming Hnvironmcnt 


63 


4. The Library System 

A coherent unified library system serves Uv facilitate die sharing of algorithms and data by imposing a 
discipline appropriate for the particular environment The Mdi Library System provides: 

- A uniform access method for referring to functions and data outside of the current logical group; 

- Lexical blocking, eliminating difficulties arising from overlap of names between different logical 
groups; 

- Automatic loading of functions for the user who knows only the name of the function which is 
wanted; 

- A facility whereby functions which may be necessary only in unusual situations arc loaded only in 
the event that they arc needed. 

The Mdi Library System may be divided into distinct parts. Ihcsc are: 

- The Package System, the collection of routines used to provide lexical blocking for a logical group 
(see section 2); 

- The ‘explicit’ loading facility, the routines used to explicitly indicate that references arc being 
made to a particular logical group; 

- The ‘implicit' (or ‘dynamic’) loading facility, the machinery for automatically loading functions 
when they arc needed during console interaction. 

4.1. Program Libraries 

In the previous discussion of the Package System and USE (see section 2.3.2), we glossed over the 
mechanism by which a PACKAGE is loaded when another PACKAGE (or the user at his terminal) refers to it 
We will now give the details. 

Ilicrc arc two types of loading common in Ml)l. programming; ‘explicit’ loading, such as USE may 
initiate, and ‘implicit* or ‘dynamic’ loading, initiated by attempting to call or examine a function that is not 
currently loaded. 

In the ease of ‘explicit’ loading, it is necessary somehow to map the name of a PACKAGE into a file name 
which contains the body of that PACKAGE. 'Che mechanism for doing so must be flexible enough to allow 
both ‘installed’ programs (those that have been debugged and submitted to the library) and developmental 
programs to be loaded. It must also be tailorablc for special needs, such as libraries for specific systems and 
personal libraries for individual users. 


4.0 



64 


'ITic Ml)l. Programming Knvironmcnt 


In the case of ‘implicit’ loading, the further mapping from the specific ENTRY of a PACKAGE referenced to 
the PACKAGE itself must be performed. It must deal with the ease of two or more PACKAGES each containing 
an ENTRY with the same PNAME. 

For programs that arc ‘public’ or ‘installed’, both of these mappings arc performed by a library. A library 
is a file which contains pointers between the names of ENTRYs of PACKAGES and the PACKAGES containing 
them, and from PACKAGE and DATUM names to the files containing them. 

The standard library is named L IBMUD and lives on a directory named L IBMUD (on El'S) or MDLL IB (on 
Tcncx/Tops-20), but other libraries, personal or special purpose, may also exist; the mechanisms for creating 
and maintaining diem arc the same in both cases. 

4.1.1. Library Searching 

When a PACKAGE is USEd, Mm first checks to see if the PACKAGE is already loaded, by looking up the 
PACKAGE name on the PACKAGE OBLIST. If the PACKAGE is not yet loaded. Mm. must search for the file 
containing the body of the PACKAGE. 

When Mdl searches, it docs so under the direction of a search path stored as the LVAL of the ATOM 
L-SEARCH-PATH. 'ITiis LVAL is a LIST, each element of which specifics ‘a place to look’ for the PACKAGE. 
These elements may be: 

- file-name * 

A STRING refers to a library file: "L IBMUD; L IBMUD" forexample. 

□ 

An empty VECTOR refers to the <SNAME> directory. The directory will be searched for files whose names are 
the name of the PACKAGE being loaded (truncated to six characters on ITS) and second names from the 
LVAL of the ATOM L-SECOND-NAMES, which is a VECTOR of STRINGS which arc possible second names for 
the file. 

[ (Unstring- or false] 

A non-empty VECTOR specifics a directory. The first element of the VECTOR gives the directory as a STRING 
or a FALSE, die latter ease meaning <SNAME>. If that is the only element, L-SECOND-NAMES specifics the 
file names to look for. If there arc odicr elements, they should be STRINGS to use in place of 
L-SECOND-NAMES. 

A search path may consist of any number of such elements. The loader will examine them sequentially, 
attempting to find die PACKAGE being loaded. 


Program Libraries 


41 



I lie MDL Programming Hnvironmcnt 


65 


The initial LVAL of L-SEARCH-PATH (on ITS) is 

( "LIBMUD" "LIBMUD; LIBMUD” [] ["MBPROG"] ["MPROG" ">"]) 
and on Tcncx/TOPS-20, it is 

("LIBMUD" "<MDLLIB>LIBMUD" [] ["MDLLIB"]) 

This instructs the loader to first search the user’s personal library (if it exists), then the ‘public’ library. Next, 
search the user’s directory for a file whose first name is the PACKAGE name, and whose second name is 
specified by L-SECOND-NAMES. If that fails, perform the same search on the library directory, and finally 
(on ITS), look for a source version of the PACKAGE on the source directory. 

Hie initial LVAL of L-SECOND-NAMES (on ITS) is 
["FBIN" "GBIN" "NBIN" ">"] 
and on Tcncx/TOPS-20, it is 

["FBIN" "GBIN" "NBIN" "MUD"] 

To give a simple example of how this mechanism may be tailored for individual needs, consider a 
programmer debugging a subsystem. If he wants his debugging versions of various PACKAGES to be loaded 
before the installed versions, he CONScs a new element onto L-SEARCH-PATH so that it contains 
([] "LIBMUD" "LIBMUD; LIBMUD" [] ["MBPROG"] ["MPROG" ">"]) 

(assuming the files with his debugging versions arc on the <SNAME> directory). 

4.1.2. Dynamic Loading 

To ease the use of ‘top level’ routines from the console, a feature is provided whereby the Library System 
can load a PACKAGE of functions automatically when one of the functions which is an ENTRY in that 
PACKAGE is invoked by name. ITiis facility is not available for use by other PACKAGES of functions, which 
must refer explicitly, via USE, to PACKAGES which they require: while a human can resolve the difficulty of 
possible multiple PACKAGES with ENTRYs of the same name, a program cannot 

When an error is generated because a FORM is evaluated, and the first element of that FORM is an ATOM 
which has no value, and the particular ATOM is in the INITIAL OBL I ST, an error handler established by the 
Library System determines if there arc any PACKAGES in the current libraries which contain an ENTRY with 
the same name as the PNAME of that ATOM. If there is one such PACKAGE, it is loaded, and the evaluation 
which got the error is continued with the correct value. If there is more than one such PACKAGE, the possible 
choices arc displayed, the user is asked which is die desired PACKAGE, and it is loaded. If there arc no 
PACKAGES with ENTRYs of the correct name, the error is not handled, and so it will fall into die standard 
error mechanism. This same procedure is also invoked when GVAL is applied to an ATOM on the I N I T IAL 


4.1 


Program Libraries 



66 


'l'hc Mill. Programming Environment 


OB LI ST and the ATOM has no value. 

4.1.3. USE-DEFER 

It is sometimes desirable to have available functions that are rarely invoked, but arc nonetheless available. 
(One example would be certain error handling routines.) 

The USE-DEFER function sets up the OBLIST path so that, when a reference is made to an ENTRY in the 
specified file, the correct ATOM is found, but the PACKAGE is not actually loaded at that time. When a 
function at a later time tries to call the function which is the value of one of the entries in this PACKAGE, the 
whole PACKAGE will be automatically loaded. USE-DEFER has two constraints which USE docs not. f irst, the 
PACKAGE must be in one of the currently active libraries; it may not simply be a file as in the ease of USE. 
Second, no reference may be made to ATOMs which arc entries but do not have values which arc applicable. In 
other words, ATOMs which arc entries because they arc data (radicr than functions) may not be referenced 
when USE-DEFER is employed instead ofUSE. 

Because USE-DEFER utilizes the dynamic loader, which utilizes the ERROR interrupts, USE-DEFER will 
not work in a demon or any other Mr>l. program which sets up its own error handlers. All such Mdl 
programs should SETG the ATOM L-NO-DEFER to a non-FALSE, which (as explained previously) will cause 
USE-DEFER to behave exactly like USE. Then, PACKAGES containing a USE-DEFER can be used without 
modification in demons and the like. 

4.1.4. USE-TOTAL 

USE -TOTAL is analogous to USE, but instead of splicing in only the ENTRY OBLIST of the PACKAGE, it 
additionally splices in the internal OBLIST. This is useful in some debugging situations, as it reduces the 
number of trailers printed and also makes the internal identifiers of the PACKAGE more accessible. 

4.1.5. Translations 

It is occasionally useful to have more than one copy of a particular PACKAGE loaded at once. One 
example that comes to mind is the ease of debugging a debugging PACKAGE, 'l’hc Library System contains a 
mechanism for ‘translating’ a PACKAGE name into another one. More specifically, it is possible to tell USE: ‘If 
you ever load the PACKAGE named foo, pretend it was named tor Instead.’ Note that this docs not change the 
searching and loading procedure described above, only the names of the OBLISTs and so on used to store the 
ATOMS in the PACKAGE. 


Program Libraries 


4.1 



flic M 1)1. Programming Knvironmcnt 


67 


<TRANSLATE old; si ring 

causes die PACKAGE old, when it is USEd, to behave as if it were named new. If new is FALSE, it means that 
old should be loaded as though it were not a PACKAGE at all; its ATOMS will appear on the DEFAULT OBLIST 
or<l .OBLIST> (normally INITIAL). 

<UNTRANSLATE old:slrinv > 
causes any translation of old to be removed. 

TRANSLATIONS) 

lists all translations currently in existence. 

^-TRANSLATIONS 
is a LIST containing all the translations. 

4.1.6. The Library Data File 

In addition to its ability to map between PACKAGES, ENTRYs, and die files which contain them, the library 
serves another purpose. If a user is compiling a function which USEs a given PACKAGE, that PACKAGE is not 
usually going to be run. All that is necessary is to examine the calling sequences of its functions, and make 
sure that all ‘side-effects’ (such as the definition of new TYPEs) occur. If only Uicsc necessary parts of the 
PACKAGE arc loaded, a great saving of time and space is effected. 

'ITic library data file provides a way of achieving this end. When a PACKAGE is added to die library, more 
information than the list of ENTRYs and the file containing the PACKAGE is collected. In particular, 
MANIFEST GVALs, NEWTYPE definitions, some MACROS, and RSUBR DECLs arc stored. Since this is the 
information used by the compiler, one can save a great deal of space and time by using information from the 
library where possible. 

If , L-USE-DATFILE is true, USE of a PACKAGE will load from the data file if possible. It is impossible if 
the PACKAGE has changed since the data file entry was created. In those cases, the PACKAGE itself is loaded 
instead. If .L-ALWAYS-DATFILE is true, an ERROR will result if the data file entry is outdated; one can 
E RRE T T to cause the real PAC KAGE to be loaded. 

USE-DATFILE is just like USE, except that it temporarily SETGs L-USE-DATFILE and 
L-ALWAYS-DATFILE to T. 

ITic data file contains, for each PACKAGE, information for each interesting ENTRY: MANIFEST GVALs, 
NEWTYPE definitions, RSUBR DECLs, and MACROS. It also has, of course, the lists of ENTRYs and RENTRYs 
needed by the dynamic loader. It does not contain other structures, nor docs it contain functions. When a 


4.1 


Program Libraries 


68 


The MIX. Programming Hnvironment 


PACKAGE is loaded from the data file, it is effectively USE-OEFERed; if you end up needing to run part of 
the PACKAGE, it will be loaded dynamically. 

Some PACKAGES can not have data file entries. If a PACKAGE defines MACROS that use data not stored in 
die data file (if die MACRO calls a FUNCTION, for example), the PACKAGE will not get a data file entry: it 
would normally end up being loaded from the file anyway. 

It is possible for a data file entry to become obsolete (if a new version of a PACKAGE is created without the 
library entry being updated). Kor this reason, the library is examined periodically for such entries and an 
attempt is made to update the appropriate entries. 

4.1.7. Run-time Switches 

There arc a number of variables which may be set dynamically to tailor the Library System’s performance. 

.L-SEARCH-PATH 

as described above (see section 4.1.1) is a LIST specifying the libraries and directories to look in, and the files 
to look for when trying to load a PACKAGE. T his variable is used by USE, USE-DEFER, USE-DATUM, and the 
dynamic loader. 

.L-SECOND-NATES 

as described above (see section 4.1.1) is a VECTOR of the second names of files to look for when attempting to 
load a PACKAGE from a directory. 

, L-NOISY 

If die GVAL of L-NOISY is non-FALSE, the names of PACKAGES and DATUMs arc printed whenever they are 
loaded, dynamically or otherwise. This feature may be turned off by SETGing L-NOISY to #FALSE (). 
L-NOISY has an initial GVAL of T. 

.L-NO-MAGIC 

Dynamic loading may be disabled by SETGing L-NO-MAGIC to a non-FALSE. L-NO-MAGIC has an initial 
GVAL of a FALSE. 

.L-ALWAYS- INQUIRE 

If die GVAL of L-ALWAYS-INQUIRE is non-FALSE, the dynamic loader will always ask the user before it 
loads anything. The GVAL of L-ALWAYS-INQUIRE is initially a FALSE. 

.L-NO-DEFER 

If the GVAL of L-NO-DEFER is non-FALSE, USE-DEFER will work exaedy like USE. L-NO-DEFER is 
initially SETGed to #FALSE (). 


Program Libraries 


4.1 



Ihc M 1)1. Programming Hnvironmcnt 


69 


4.1.8. Library Utility Functions 

A number of functions exist which allow the user to examine libraries, list their contents, and retrieve their 
entries. All of the functions below except L-PATH and L-OBL accept an optional STRING argument, a 
library specification. If it is defaulted, they operate on the public library, specified by the string "LIBMUD; 
LIBMUD" or " <MDLL I B> LIBMUD". 

<L-L0AD oackaee:strinc library:slring> 

L-LOAD requires a STRING (the name of a PACKAGE or DATUM) and attempts to load it from library (if 
given) or the current libraries, as per L -SEARCH- PATH. 

<L-FIND fundion-mmmstrine library: stringy 

L-FIND requires a STRING (the name of an ENTRY), returning a UVECTOR of two-element VECTORS of the 
form: 

[ package- in- which- fund ion- exists: string 
library'- in- which- package-existststring] 

This finds all of the entries which have the same PNAME but arc in different PACKAGES. 

The remaining functions arc in the PACKAGE "L", rather than in the PACKAGE "PKG". For each of 
these, the optional library argument is by default the library; that is, "LIBMUD; LIBMUD" or 
"<MDLLIB>LIBMUD". 

<L-F ILE packace:strine library: stringy 

L-FILE requires a STRING (the name of a PACKAGE or DATUM) and returns a STRING which is the file 
specification of the file, pointed to by the library, which contains the body of that PACKAGE or DATUM. 
<L-WHERE vackatie:strine library: stringy 

L-WHERE is similar to L-FILE but returns a VECTOR of STRINGS which is the actual complete file 
specification of the file containing the PACKAGE (i.c., the ‘real’ slots in a CHANNEL open to the file). 
<L-LISTE library:string> 

L-LISTE prints the names of all of the entries of all of the PACKAGES in the library. 

<L-LISTP library:string> 

L-LISTP prints the names of all of die PACKAGES and DATUMs in the library. 

CL-COUNTE library: string> 

L-COUNTE returns a FIX, the number of entries defined by all of the PACKAGES in the library. 

<L-C0UNTP library: string> 

% 

L-COUNTP returns a FIX, the number of PACKAGES and DATUMs in the library. 


4.1 


Program Libraries 



70 


The Ml)l. Programming Knvironment 


<L-LISTPE nackaee-strine library: string) 

L-LISTPE requires a STRING (ihe name of a PACKAGE) and prints the names of all of its entries. 

<L-PATH> 

L-PATH prints a list of the names of all of the OBLISTs in the user’s current OBLIST path. 

<L-OBL atom ) 

L-OBL requires an ATOM and returns an ATOM, the name of the first ATOM'S OBLIST. L-OBL is in fact 
<GET <OBLIST? atom) OBLIST> 

4.1.9. Internal Library Functions 

There are several internal functions used for searching libraries (which is, aficr all, all the l ibrary System 
ever does). 

<PACKAGE-FIND oackavc:slrina librar\:strine > 

searches library for jxickage. If there is no such PACKAGE or DATUM in library, it returns a FALSE. 
Otherwise, it returns a STRING, which is the name of the file containing package. 

<ENTRY-FIND enln’.slrina-oratom library: strine ) 

searches library for PACKAGES containing entry. It returns a FALSE if there arc none, otherwise a L I ST some 
multiple of four elements long, where each set of four elements describes a package containing an ENTRY 
with that P NAME. These elements are: 

ixtckagr.slring is the PACKAGE being described. 

file-namc:siring is the file-name containing the package. 

rpackage?:atom-orfalse indicates, if non-FALSE, that the package is in fact an RPACKAGE. 
rentry?: atom- or- false indicates, if non-FALSE, that the entry is an RENTRY. 

<DEFER-FIND uackaee:strine librarv.slrine ) 

returns a FALSE if the PACKAGE or DATUM is not found, or a VECTOR of five elements describing the 

PACKAGE. 

rpackage?:alom-or false indicates, as above, whether the package is an RPACKAGE. 

name:slring is the name of the package. 

file- name: string is the file containing the package. 

entries: list is a L I ST of the PNAMEs of the ENT RYs of the package. 

renlries:lisl is a L I ST of the PNAMEs of the RE NTRYs of the package. 


Program Libraries 


4.1 



The MDL Programming Hnvironment 


71 


ITiis is ail the information about the package that the library contains. 

4.1.10. Library Maintenance 

The PACKAGE called "LUP" contains functions used to modify libraries, and to add, update and delete 
PACKAGES and DATUMs. It should be noted that libraries do not contain the bodies of PACKAGES and 
DATUMs. Rather, they point to files which contain these. 

<LUP-ACT library: strin£ > 

requires one argument, a library specification STRING, and activates the library so specified. If the library 
doesn’t exist, it is created. In order to protect the library from loss due to system or Mm. crashes, activating a 
library for modification copies the library data files and locks the library so that no one else may modify it. 
Modifications arc made to the copies, which arc renamed back over the originals only when the library is 
explicitly deactivated. Obviously, PACKAGES added to a library aren't available, even to the person adding 
them, until the library is deactivated. 

<LUP-DCT> 

deactivates the currently active library. 

<LUP-ADD-PACK package- file:strine 

update?: boolean 

datfile-entry?:boolean> 

package-file is a file specification of the file containing the body of the PACKAGE to be added. 
LUP-ADD-PACK will find the PACKAGE statement within the file (or complain if it can’t). 

update? is optional, and if non-FALSE, it allows the PACKAGE to update an older version of itself, 
something which is not otherwise allowed. Note that, since the library points to the file which contains the 
body of the PACKAGE, that file should not be deleted later, else the library won’t be able to find it 

dai file- entry? is by default T, but if it is FALSE, no entry will be created in the datfilc for this PACKAGE. 
Since datfilc entries arc generally useful only in the compiler (and similar environments), it doesn't do much 
good to have them for PACKAGES that arc only called from top level (c.g., F INDATOM). 

When adding a PACKAGE to the public library, the PACKAGE’S object file should be copied to the 
appropriate library directory ("LIBRM/i" on ITS, or "<MDLLIB>" on Tops-20) and the library pointed at 
that copy of the file. If no library is activated when LUP-ADD-PACK runs, it will activate "LIBMUD; 
LIBMUD" or "<MDLLIB>LIBMUD". 


4.1 


Program Libraries 



72 


The M 1)1. Programming Hnvironment 


<LUP-ADD-DATUM mme:sirine 
file:s(ri>w 
update?:booIeari> 

is analogous to LUP-ADD-PACK, adding a DATUM to the active library. LUP-ADD-DATUM requires two 
STRING arguments, the name of the DATUM and the specification of the file which contains the body of the 
DATUM. LUP-ADD-DATUM will accept the same optional argument that LUP-ADD-PACK accepts, with the 
same meaning and default. The same restrictions concerning the file w hich contains the DATUM also apply. 
<LUP-DEL Dackaue:slrine > 

LUP-DEL requires one STRING argument, the name of a PACKAGE or data set, and deletes that PACKAGE or 
DATUM from the currently active library. LUP-DEL docs not touch the file containing the body of the 
PACKAGE or DATUM. 

<LUP-MOVE Dackaac.slrine Cile:s(rine > 

causes the file pointer of package to be changed to point to file. Ibis is a faster operation than re-adding the 
PACKAGE, and it is intended for situations in which an existing library file has been moved for sonic reason. 
CLIB-GC librarv:strine > 

garbage-collects the library in question, if tills is required. Garbage-collection is occasionally useful since it 
causes all the elements of each hash bucket to live near each other in the library file, thus improving 
performance during searches. It also allocates some free storage ir each page of the file. 

4.2. The Pure-mapping Library 

The basic idea behind Mot. pure mapping is to separate out the code part of RSUBRs in compiled 
programs. The RSUBRs themselves arc kept in a file known as an FBIN (sec 6.3). Ilicsc RSUBRs do not 
contain the code but instead point to a file which contains the code. This scheme has several advantages. 
First, the code can be dynamically mapped in when needed. 'Ibis allows Mdi. to use more code than will fit 
in the virtual address space of the machine it is running on. Secondly, since die code is pure it can be shared 
between several Mdis using it Finally, the FBIN file itself is smaller than a corresponding NBIN file and 
therefore F LOADS more rapidly. 

In the most basic implementation of FBINs, there arc three files: the FBIN, the SAV file (which contains 
the code), and the FIXUP file, which contains the information necessary to update the SAV FILE for new 
releases of Mdl. As is obvious, this entails a lot of flics, and potentially a lot of flic directories. The Mdl 
Pu re-mapping Library reduces this storage overhead by collecting all of the SAV and FIXUP files together. 

The scheme uses two large data bases, each contained in one file. The data bases arc called ‘SAV’ and 
‘F IXUP’. These files store all currently existent SAVs and FIXUPs for all existing versions of Mdl. Each data 


Program Libraries 


4.1 



I'hc MI)L Programming Knvironment 


73 . 

base is structured like a file system. There is a main ‘directory’ dial points to a number of other ‘directories’, 
each of which points to a number of ‘files’ inside the data base. In this section the word ‘file’ or ‘directory’ in 
quotes refers to an object inside a data base. 'Hie files containing the data bases arc named (on ITS) 
"MUDSAV;SAV FILE" and "MUDSAV; FIXUP FILE". On Tcncx/TOPS-20, they are 
"<MDL>SAV. F ILE" and "<MDL>FIXUP. FILE". 

4.2.1. The Demon 

While all Mills can read from die Pure-mapping Library, there is only one program which can write into 
it. This is a maintainCr demon which runs once a day to keep the Library updated. This demon can add ‘files’, 
delete ‘files', and add ‘subdirectories' to both data bases. 

To facilitate updating of the library there is a directory on which to put files to lie added as well as files to 
indicate what is to be deleted. iTiis is the "MUDTMP" directory on ITS and the ”<MDLLIB>" directory on 
Tcnex/TOPS-20. Any file on it with the second name of SAV/m/i or F IX/»/// (where nnn is a 2 or 3 digit Mill, 
release number) will be added to the appropriate data base. If the files "DELETE SAVS" or "DELETE 
F I XUPS " exist, then they will be used to delete ‘files’ from the data bases. These files must be ASCII files of 
the form 

filename 1 [SPACE] filename 2 [CRLF] 

An example of a valid delete file is as follows 

NCODGE SAV53 

1NC0DGE SAV53 

iTic demon will ignore any deletion requests for ‘files' not in the data base. 

The demon docs its work in several passes. The basic passes arc the delete pass, the planning pass, the 
update pass, and the salvage pass. The delete pass deletes ‘files’ if either a "DELETE SAVS" or "DELETE 
FIXUPS" file exists on its working directory. The planning pass builds a plan file by examining the working 
directory and calculating where new ‘files' will be placed in the data bases. The planning pass builds two files 
using a special internal format These files will be used by the update pass to add ‘files’ to the data bases. 'The 
planning pass also enlarges die data base files as much as necessary to accomodate the new ‘files’. The update 
phase reads the plan files and adds new SAV and FIXUP ‘files’ to the data bases. If a ‘directory’ overflows, a 
new ‘directory’ is added during this pass, and all the ‘directories’ arc recreated (i.c., all the ‘files’ have to be 
rehashed, since they were originally placed in a ‘directory’ according to a hashing algorithm based on the 
number of directories’). The salvage pass is used to pick up any free storage that has been lost through system 
crashes or lost through holes created during the updating of the data bases. 


4.2 


TTic Pure-mapping Library 


74 


’ITic Ml)l. Programming Hnvironmcnt 


Throughout the entire processing of the data bases attempts arc made to keep the data bases in a consistent 
state. ‘Directories’ arc updated only after ‘files’ arc guaranteed to be in the data bases. The plan files described 
arc used to keep the data bases consistent in ease the system crashes while the demon is in the update pass. 

A major goal in the design of the data bases is to allow recovery in ease of demon errors or system disk 
crashes. To this end the data bases arc backed up on tape every other week. (It would be dumped more often 
but the file is currently over two million words long). This of course leaves the problem that ‘files’ added to 
the data bases between dumps could be lost in a disk crash. To aid in recovery from such a crash, all Tiles’ 
added between dumps arc copied to the "MUDRST" directory (on ITS) or the "<MDL.SV>" di recto 17 (on 
Tcncx/TOPS-20). Moreover a file is kept listing all the ‘files' added during the previous week. This file is 
called "ADDED FILES". All this information is deleted once the data base is dumped to tape. 

4.2.2. User Programs 

Occasionally it is useful for a user to list the data base ‘directories’, to see if certain ‘files’ arc in it, and copy 
'files’ out of the data base. DBMAIN is a program which allows the user to do these things. 

The following arc functions available to the user. 

4. 2. 2.1. Listing Functions 

<CLISTF data-base:string> 

is used to list all the ‘files’ in a data base. It takes one optional argument which is the name of the data base 
(either "SAV" or "FIXUP"). If no argument is supplied, "SAV" is used by default. ( ITiis is always the 
default whenever a function takes an optional argument specifying the data base.) CLISTF prints each ‘file’, 
its length, and where it is located. The format of a line of listing is as follows: 
fill fn2 size block 

where fill is the first ‘file’ name, fn2 is the second ‘file’ name, size is the length of the ‘file’ in blocks (1024. 
words for SAVs, 256. words for FIXUPs), and block is the block at which the ‘file’ starts. This is the format 
used whenever listing ‘files*. 

<LISTF data-base: string directories> 

is used to list all the ‘directories’ of an entire data base. It Likes two optional arguments, the data-base to be 
listed, and a specification of which 'directories' to list, 'lhc 'directories’ may be: 

a FIX: list the ‘directory’ specified by the FIX; 

a L 1ST of F IXs: list the ‘directories’ specified in the L 1ST; 

the ATOM ALL: list all the ‘directories’ (this is the default). 


The Purc*mapping Library 


U 



1 he Ml)l. Programming Hnvironment 


75 


<FLIST da la- base: stringy 

lists free areas of storage in the data base. It lists the free storage in the form: 
length block 

where length is die length of the area of free storage and block is the block number of the starting block. This 
function takes one optional argument which is the name of the data base to be examined. At the end of the 
listing it will tell the total amount of free storage. 

4.2. 2. 2. Find Functions 

<FIND-FILE file: st line data-base: stringy 

is used to find a specific ‘file’. It takes as its argument a ‘file’ specification and prints the ‘file’ name along with 
die information printed by the listing functions if the ‘file’ exists, otherwise it returns an object of type 
FALSE. The ‘file’ specification must be of the form: 

” dir; fnl fin2” 

where dir is either SAV or FIXUP and fnl and fn2 arc the first and second ‘file’ names respectively. 
<SPEC-FIND fnl: st rim: data-base:string> 

is used to find all ‘files’ with the same basic name, disregarding die leading digit(s) which arc added to make 
‘file’ names unique. It takes one required argument which is the fnl to look for. It takes an optional second 
argument which is the data-base to look in. For example die call 
<SPEC-F IND "MAIL"> 
might print: 

MAIL SAV53 8 140 

1MAIL SAV53 8 360 

4.2. 2. 3. Other Functions 

<DELETE filc.’slrine data-base:slringy 

allows the user to delete a ‘file’ from a data base. It takes the same type of ‘file’ specification that FIND-FILE 
takes. Hie ‘file’ you specify will be deleted the next time the demon diat maintains the data base runs. 

<GET-FILE filc:slrine oitinut:strine dala-base:string> 
allows the user to retrieve a ‘file’ from the data base. It takes two arguments. 'Hie first is the ‘file’ specification 
of die file to retrieve out of the data base and the second is the output file you wish to copy it to. 

<STATUS> 

gives the information about the state of die data bases. It tells the number of ‘files’ and the amount of free 
storage in each data base. STATUS Lakes no arguments. 


4.2 


The Purc-mapping Library 



76 


The MI)L Programming Hnvironment 


4.2.3. Using DBMAIN 

There are several ways to use DBMAIN. It can be used by typing 
: DBMAIN function argl ... argn 

to DDT. The jcl-line is of the form J unction argl ... argn, where function is die name of the function to be used. 
For example 

.DBMAIN FLIST "FIXUP" 

will list die free storage block for the "FIXUP" data base. DBMAIN will kill itself after finishing and can be 
killed earlier by typing ts. 

The jcl-line mentioned above can be modified to allow output to be routed to a file. This can be done by 
preceding the normal jcl-line with a string specifying the file name of the output file. 

: DBMAIN "LISTOF SAVS" CLISTF 

will produce a listing of the files in die SAV data base and will print this information to the file "LISTOF 
SAVS". 

4.2.4. Garbage Collection 

One problem of the Mm. Purc-mapping Library is that many useless SAV and FIXUP ‘files’ remain as new 
revisions of user programs are created. To alleviate Uiis problem there is a garbage collection system for the 
data bases. 

'The major goal of this scheme is to determine which ‘files’ in the data bases arc no longer useful. To do 
this all files in the system arc scanned to see what SAV files arc still pointed to (not including those pointed to 
only from within ITS archive files). A SAV ‘file’ can be pointed to from FBIN files and SAVE files. A SAVE 
file contains pointers in its PURVEC (Pure VECTOR). All FBIN files should begin with something of the form 
’<PCODE ftle:slring> 

where fie is die name of the SAV ‘file’ associated with this FBIN. If an FBIN has more than one SAV ‘file’ 
associated with it then there can be several PCOOE FORMS at the beginning of the file. For purposes of 
garbage collection, this FORM (or FORMS) must be retained whenever an FBIN file is edited. If these PCODE 
FORMs disappear, their pointers to the SAV ‘files’ will go with them, and the SAV ‘files’ might be garbage 
collected. 

Garbage collections proceed by looking at every file on the disk, building a list of all ‘files’ pointed to. The 
program then examines the data bases and any ‘files’ which arc not pointed to arc deleted. 

It is possible that deletions can fragment the free area in the data bases. If compaction becomes necessary, 


The Purc-mapping Library 


4 2 



The MDI. Programming Knvironment 


77 


there exists a routine to do in-place compaction of the data bases. 

4.2.5. Internal Structure 

The "SAV" and "FIXUP" data bases have similar formats. The ‘files' in the data base are pointed to by 
entries in what is essentially a hash table. Associated with each data base is a main ‘directory’ (the hash table). 
This ‘directory’ is located in the first 1024 words of the file. ITiis main ‘directory’ points to other ‘directories’ 
in the data base (the hashing buckets). Kach of these ‘directories’ is 1024 words long. The first ‘file’ name is 
used to determine which ‘directory’ the ‘file’ is on. The structure of the main ‘directory’ is as follows. 

word 0/ number n of entries in the main ‘directory’ 
words 1-n/ block number of each ‘directory’ 

ITicrc can be up to 1023 ‘directories’ and each of these can contain approximately 500 ‘files’. This provides a 
virtually unlimited ‘directory’. 

Word 0 of each ‘directory’ gives its length in words. From Word 1 on arc ‘directory’ entries. All entries 
have the same two word format. Ihc first word contains the the first ‘file’ name in SI XB IT. The second word 
contains the following fields: 

length of die ‘file’ in blocks (a block for a SAV ‘file’ is 1024 words long while a block for a FIXUP ‘file’ is 256 
words long) (bits 1-6) 

version revision of Mdl til is ‘file’ belongs to (bits 8-17) 
block in the data base where this ‘file’ starts (bits 18-35) 

The ‘directories' are sorted by strict numerical ordcr(c.g., AAA SAV53 comes before 1AAA SAV53). 

F-ach data base contains a free storage table. This table occupies the second 1024 words of the data base. 
The first word of die table is the number of entries in the free storage table. The remaining entries define 
areas of free storage. These arc of die form 
length, , block 

where length is die number of blocks for diis free area, and block is the block number at which it starts. 

llicrc arc two major differences between the "SAV" data base and the "FIXUP" data base. The first deals 
with block sizes. In the "SAV" data base the block size is 1024 words. In the "FIXUP" data base the block 
size is 256 words. This smaller size allows for more compaction of these small ‘files’. 

Ilic second major difference is that while there can be many versions of the same ‘file’ in the "SAV" data 
base (c.g. NCODGE SAV53 and NCODGE SAV54), there can only be one version in the "FIXUP" data base. 


4.2 


'ITie Purc-mapping Library 



78 


Ilic MI)L Programming Knvironment 


This will be the FIXUP Tile’ most recently added. Hie corresponding SAV ‘file’ for this FIXUP Tile’ should 
exist to allow the SAV file to be updated for future Mro. revisions. 


'Hie Purc-mapping Library 


M 



The M 1)1. Programming Rnvironment ' 


79 


5. The Compiler 

The purpose of the Mm. compiler is to transform interpreted Mm. code into assembly language. The 
compiler comes in several incarnations for various purposes. 

PCOMP is a program which runs the ‘installed’ compiler -- that is, the one which is most debugged, supported, 
and otherwise official. Hie *P‘ stands for purified,’ incidentally. 

NPCOMP is a program which runs a newer, less well-debugged compiler, if there is one. NPCOMP is often 
where development work of one sort or another is being debugged. 

The ‘Batch Compiler,’ often called Combat, though strictly speaking the name refers to a different program 
(see section 5.2) is a program that compiles, at night, those compilations that have been queued for it. 

The remainder of this chapter describes the specifics of interaction with the compiler, including a section on 
its internals. 

5.1. Interfacing to the Compiler 

TTic operation of the Mm. compiler is controlled by a few very high-level functions and a sometimes 
bewildering array of ATOMs whose values arc switches and data. This section will describe each such ATOM 
and its use. The reader should bear in mind that in the normal ease he will be using Combat to set up his 
compilations and thus will not have to deal directly with diese ATOMs and calls. 

5.1.1. Compiler Functions 

<COMPILE source: function- orlisl output: channel 

is the lowest level call to die compiler. It compiles exactly one FUNCTION (or a LIST of them) and prints the 
generated code on die CHANNEL given as the second argument COMPILE is used primarily for compiler 
debugging. 

<FILE-COMPILE u mLsiim L mim Lsim g> 

FILE-COMPILE attempts to provide a convenient interface between the user and the compiler, '[he user 
simply gives FILE-COMPILE the name of an input file, and it can do all die rest The user may specify other 
information about output files, compiler modes, etc., but if he doesn’t, reasonable assumptions arc made. 

FILE-COMPILE works in the following way. First it reads in the input file and collects into a LIST the 
names of all of the defined FUNCTIONS that it finds. It soils diis LIST based on which FUNCTIONS call 
which other FUNCTIONS. The FUNCTIONS which call no other FUNCTIONS arc at the beginning of the 
LIST, followed by those that only call FUNCTIONS that call no other FUNCTIONS, and so on. Groups of 
FUNCTIONS that are mutually recursive are collected in L ISTs subordinate to the main L I ST. 


5.0 



80 


The MIDI. Programming Environment 


Each FUNCT ION will produce a separate RSUBR. COMPILE is called successively on each member of the 
LIST of FUNCT IONs. LISTs of mutually recursive FUNCTIONS arc also passed to COMPILE. 

After each FUNCTION or LIST of FUNCTIONS is compiled, the resulting RSUBR is written into a 
temporary file to enable more convenient crash recovery. This file is written in such a way that, no matter 
when the system crashes, the contents of the temporary file arc guaranteed to be in a consistent state. 

When all is compiled, FILE-COMPILE writes out an output file which is identical to the input file except 
dial all FUNCT IONs have been replaced with their compiled counterparts. If any of the FUNCT IONs did not 
compile due to programmer errors or compiler bugs, those FUNCTIONS arc left unchanged in the output file. 

IDuring its operation, FILE-COMPILE maintains a "RECORD" file which contains all of the messages, 
warnings and error messages produced by the compiler. It may optionally produce a listing of the object code 
produced, in Mni assembler format. Ibis is primarily useful for compiler debugging. (Note that a somewhat 
less complete listing may be made at a later time. See section 7.3.) 

On IT’S, FILE-COMPILE usually runs as a demon called COMBAT ZONE. In dais ease another interface 
called FCOMP resides above FILE-COMPILE. 'Ibis interface reads files that arc compilation specifications 
and passes them to F ILt-COMPILE. 

< FCOMP %. INCHAN inmil-file outDUl-Me > 

As most compiler usage is based on Combat plan files, FCOMP is the most-seen driver of the compiler. (Note 
that the % in front of . INCHAN causes the CHANNEL the PLAN file is being read from to be passed as one 
argument to FCOMP.) 

<STATUS> 

is an informational function; it tells how far the compilation of a given group has progressed, which 
FUNCTION is being worked on, and how many FUNCTIONS remain to be compiled. It also prints the 
accumulated real time and epu time since the beginning of the compilation. Obviously, you must tG the 
compilation to use it, but sec section 8.3. 

5.1.2. Compiler Switches 

The calls to the various compiler drivers arc rather short, for the simple reason that the controlling 
in formation is passed to the compiler as the L VALs of a set of AT OMs. 


Interfacing to the Compiler 


5.1 



The MD1. Programming Hnvironment 


81 


<SET DEBUG-COMPILE!- boolean ) 

(by default FALSE) causes the compiler to generate extra information about what it's doing. This information 
is in the form of ‘warnings’ produced when the compiler was forced to generate less than optimal code. For 
example, invocations of the arithmetic SUBRs can be open-compiled if the variables used can be determined 
to be exclusively Fixes. r lhc debugging compiler will warn you if it is forced to resort to less efficient 
arithmetic calls. 

<SET PRECOMPILED!- file: string) 

Often, a file of FUNCTIONS has been compiled before, and now only a few FUNCTIONS have been updated 
and need to be compiled again. Most of the file is already correctly compiled: it is quite wasteful to recompile 
the entire thing. If a PRECOMPILED is given, the file is loaded before compilation; any functions which have 
corresponding RSUBRs in the precompilation, and which arc not on the REDO list, arc not recompiled. It is 
appropriate to specify the temporary file as a precompilation if your previous compilation was interrupted by 
a system crash. 

<SET REDO!- list-of-atoms ) 

REDO is a LIST of FUNCT ION names to be recompiled, regardless of whether or not they arc compiled in the 
precompilation. In conjunction with PRECOMPILED and PACKAGE-MODE, REDO allows compilation of 
precisely those FUNCTIONS which have been changed since the last compilation. Note that COMBAT will set 
up these values morc-or-lcss automatically in most situations. 

<SET PACKAGE-MODE!- string) 

This should be the name of a PACKAGE, which is assumed to be the PACKAGE being compiled. FUNCTION 
names in the REDO LIST will be looked up in the appropriate PACKAGE OBLISTs if this flag is set, thereby 
saving some typing of trailers. 

<SET TEMPNAME I - file.'slring) 

The compiler writes intermediate results to the temporary file, which is normally the file n sname\fjnm >" on 
ITS, where fnm is the first name of the input file. It Is rarely (if ever) necessary to change that default 
<SET SOURCE!- Jile.string) 

Setting this switch causes the compiler to write out the assembler input it generates. This is sometimes useful 
for compiler debugging. On ITS, such output normally goes to ”sname;fnin SOURCE", where fnm is the 
first name of the input file. 

<SET SPECIAL!- boolean) 

Ihc compiler nonnally assumes that variables which aren’t declared SPECIAL aren’t SPECIAL. This means 
that they will be available only to the RSUBR in which they arc declared: SPECIAL variables arc bound on 
the control stack, just as all variables arc in interpreted code. If this flag is T (by default FALSE), all variables 
will be assumed to be SPECIAL unless declared otherwise. This is analogous to SPECIAL-MODE being 

Interfacing to the Compiler 


5.1 



82 


1'hc M 1)1. Programming Knvironment 


SPECIAL, and it is not recommended that any code be written using this convention. 

<SET EXPFLOAD! - boolean > 

If true, FLOADs in the file being compiled will be expanded at load time: what was FLOADed before will be 
treated as part of the file. EXPFLOAD is examined by GROUP-LOAD, and not the compiler itself. The default 
is FALSE. 

<SET EXPSPLICE 1 - boolean . > 

If true, objects of type SPLICE (primtype LIST) which arc encountered in the course of EVALing the forms 
processed by GROUP-LOAD will be spliced directly into the group; it is therefore a lot like EXPFLOAD. 
EXPSPLICE is examined by GROUP-LOAD, and not the compiler itself. ’ITtc default is therefore FALSE. Its 
only known use has been to make functions at load time and have them compiled. 

<SET CAREFUL!- boolean> 

Defaults to T. If FALSE, the compiler will omit most of the bounds-chccking code it normally generates for 
NT FIs, PUTS, and so on. This obviously will make the compiled code run faster, but also makes debugging the 
compiled code nearly impossible. 

<SET REASONABLE!- boolean> 

Defaults to T. If FALSE, the compiler will generate reasonable code only if everything ever called from the 
functions being compiled is loaded into the compiler. A call to a function not loaded produces an EVAL of a 
FORM, thereby ensuring that such constructs as "CALL" in the called function will work correctly. Ibis is 
admittedly pretty unreasonable (if not paranoid), whence the name of the switch. 

<SET GLUE!- boolean . > 

Defaults to T. If FALSE, the compiler will not generate GLUE bits. As you always want GLUE bits, there is no 
reason to ever change this. 

<SET MACRO-COMPILE!- boolean> 

Defaults to FALSE. If non*FALSE, the compiler will compile MACROS into RSUBRs. This doesn’t change 
anything produced by macro expansions, but docs cause the expansion to speed up. Since the compiler 
expands the macro and then compiles the expansion, this is rarely useful. 

<SET MACRO-FLUSH!- boolean> 

Defaults to FALSE. If non-FALSE, MACROS which appear in the file being compiled will not appear in the 
resulting NB I N. Ibis saves space, at the expense of making debugging harder. 

<SET MAX-SPACE 1- booleari> 

Defaults to FALSE. If non-FALSE, the compiler flushes from core most of each RSUBR once it has been 
compiled; only the DECL is needed to help compile other functions. Since the entire RSUBR is written out in 
the temporary file, no information is losL 'Ibis can, for compilations which are too large, result in 
considerable improvements in speed, primarily because more space is available in the Mdl and less time is 


Interfacing to the Compiler 


5.1 



The M 1)1. Programming Bnvironment 


83 


spent in the garbage collector. 

<SET HAIRY-ANALYSIS1 - boolean> 

t 

Defaults to T. If this is not set, the compiler will not perform the complex type checking it usually does. If 
HAIRY-ANALYSIS is FALSE, the code will be generated faster, as type-analysis is expensive, but will not 
execute as fast 

5.2. COMBAT 

The usual method of dealing with the compiler is through the program Combat, whose specialty is the 
preparation of ‘plan files’ to be loaded by the compiler. Combat is a program which knows about each of the 
previously described compiler switches and the interactions among them. It has an easy-to-use interface, an 
ability to store commonly used ‘plan files’ as compilation types , and in general is designed to make using the 
M 01 . compiler a less-cumbersome task. 

5.2.1. User interface 

COMBAT’S user interface is patterned after, though not identical to, a CALICO interface [1). In particular, it 
expects in response to any given prompt a particular type of input from the user, which may be a file name, a 
‘symbol’, or text Ordinarily, the type of input expected is indicated by the ‘syntactic prompt’ which follows 
the normal prompt; this is one of ‘( FILESPEC)’, ’( SYM)’, and ‘(TEXT)’. The ’Toggle verbosity’ compilation 
type turns the printing of the syntactic prompt on and off, and causes a tailor file to be written out when used. 

A number of special characters arc defined for any of these types of input 
t@: Clears the input buffer, as in MDL. 
tD: Redisplays the input buffer, as in Mdl. 
tL: Clears the screen and redisplays the input buffer, as in Mdl. 

tG: When given as the first character of an answer, allows one to get the answer from a user-defined type. 
See the section on tailoring. 

tQ: Has special effects when a compilation plan is being made (see below). See also the section on file name 
input 

tR: Causes COMBAT to ‘back up'. Typically this means go to the previous question asked, but in certain 
modes it may have a slightly different effect. When a Mudcom is running, this kills it and backs up to the 
last question asked. 

tS: Abnormally ends whatever is being done, and returns to the ‘Type of compilation’ question. If a 
Mudcom is running, it will be killed. When a long compilation plan (‘How to run’ is ‘Many’) is being 


5.1 


Interfacing to the Compiler 



84 


ITic M 1)1. Programming Hnvironmcnt 


made, the portions already made will be saved. See the ‘Rush many’ compilation type. 

?: When given as the first character of an answer, this causes a more detailed description of what is expected 
to be printed, along with the current default and hqw to obtain it 

\: ITiis quotes whatever character follows it, including DEL, ESC, etc. It does not have the effect of quoting 
strange characters in file names; see the section on file name input. \, used as a quote character, never 
echoes, and cannot be rubbed out 

In addition, when the syntactic prompt is ( SYM), tF is useful (sec below). 

5. 2. 1.1. Symbolic irtput 

If you arc familiar with CALICO, this section can probably be skipped. When entering symbolic input, 
one need only type the characters required to uniquely specify the desired choice: the interface will complete 
the response, and in addition can display the available choices at any point. 

SPACE completes the response as far as it can. If the response is uniquely specified, it will be displayed in 
its entirety, followed by * !’; if more titan one choice is still possible, then the portion of those choices which is 
unambiguously specified will be displayed, followed by ’&’. For instance, if ‘Expand floads’ and ‘Expand 
splices’ arc among the choices, and ‘Ex SPACE’ has been typed, ‘Expand &’ will be displayed if the ‘Ex’ 
reduces the choices to those two. 

In some eases, if SPACE is the first character typed, it will select the default (first) choice and terminate. 
When tF is typed, all remaining choices will be displayed. 

To terminate responses in this mode, either ESC or CRLF may be used. In either case, the current 
response is completed as far as it can be. If only one choice then remains, the answer is terminated and the 
single choice will be used. If more than one choice is possible, it is just as if SPACE had been typed. 

Typing ESC or CRLF before any other characters have been entered causes the default answer to be used. 

5. 2. 1.2. Filenames 

File names arc expected in the standard dev: smvne\fnamel fname2 format on ITS; on Tcncx/TOPS-20, 
standard file name recognition is used. Typically, typing simply ESC or CRLF answers ‘no’ to the question, 
while SPACE ESC says ‘use the default’. In certain special eases (’Input file’ and ‘Output file’), when some 
answer to the question is imperative, the default will be used in either ease. File names should not be 
surrounded by quotes in this mode; they arc not Mdl STRINGs! 


COMBAT 


5.2 



The M 1)1, Programming Hnvironment 


85 


It is rather painful to get funny characters (such as SPACE) into file names. When the file-name parser 
sees a tQ, it uses the following character in the name being generated regardless. Unfortunately, the tQ must 
be quoted to get it past the reader, since it has special effects in the normal ease. r ITius, the file name given to 
M DL as " T AA ; F00 > " has to be typed to COMBAT as T AA ; \ tQ F 00 > . 

5. 2. 1.3. Text 

Text is just that: relatively arbitrary characters, terminated by ESC. Since CRLF is allowed in text, it docs 
not terminate input. Text type input is used in a number of eases where it isn’t quite appropriate, such as the 
‘Redo list’ and ‘Package mode’ questions. If it is known that the expected response is a LIST or STRING, as 
in those eases, the appropriate brackets or quotes should not be typed. 


5.2.2. Combat Questions 

This section discusses the questions that can be asked of the user during the preparation of a Combat plan 
file, which is FLOADed by the Combat demon or by PCOMP to effect a compilation. The perceptive reader 
will notice a strong resemblance to section 5.1.2, in which the switches relevant to the compiler are listed. 
Questions asked by the pre-existing compilation types (‘Verbose’ and 'Short') arc so indicated. All questions 
arc available in user-defined compilation types (see section 5.2.5). 

‘Sname’: sets the default directory for questions that want a file name as an answer; also causes the FORM 
<SNAME snatne > , where sname is the answer given, to be included in the plan. This sets the default 
directory for files referenced by the compiler; it also causes the temporary file (sec below) to go to the 
sname directory. 

‘Use new compiler?’ (Verbose and Short): specifies whether the ‘new’ compiler or the ‘old’ compiler should 
be used. Often, when there is only one compiler, this question will not be asked. If answered 
affirmatively, it causes the FORM 

COR CGASSIGNED? EXPERIMENTAL 1 -> <NEWC0MPl-» 
to be included in the plan. This FORM will load a new compiler on top of the old if necessary. 

‘Debugging compiler?’ (Verbose): causes DEBUG-COMPILE 1 - to be set to T, which causes the new compiler 
to generate extra information about what it’s doing. 'This currently is asked only if the ncw-compiler 
question is answered affirmatively. 

‘Input from’ (Verbose and Short): the file to be compiled. This appears in two places in the plan: as 
CSETG COMBAT!- input-file> 
and in the call to FCOMP described below. 

‘Output to’ (Verbose): the file name to be used for the NBIN. The default is the input file name, with NBIN as 
the second file name instead of whatever it was for the input. This completes the call to FCOMP that ends 
every plan: 


5.2 


COMBAT 



86 


The Mill, Programming Knvironment 


<FCOMP %. INCHAN input-file output- file > 

This call is what actually invokes the compiler. 

'Precompilation from’ (Verbose): specifics a file containing a previously compiled version of the input file. 
Any FUNCTIONS which have corresponding RSUBRs in the precompilation, and which arc not on the 
‘Redo’ list, arc not recompiled. It is appropriate to specify the temporary file as a prceompilation if your 
previous compilation was interrupted by a system crash. Sets PRECOMPILED! -. 

‘Compare with’ (Verbose): This question is asked only if a precompilation file is specified. If answered 
affirmatively (user types either SPACE ESC or a file name) MuiX'OM (see section 8.1) will be run with jel 
of the input file name, and the file name provided here (the default is as for precompilation), plus some 
extra stuff specified below. If ‘F00 NBIN’ is given here, then MuiX’OM will look for the newest revision 
of F00 which was created before the NBIN. Muixom determines which FUNCTIONS in the file have 
changed and therefore need to be recompiled. It also determines whether the file is a PACKAGE, and 
answers the 'Package inode’ question appropriately. It is therefore not usually necessary for the user to 
answer the ‘Redo’ and 'Package mode' questions directly. 

‘Cheek macros?’ (Verbose): asked only if 'Compare with' is answered affirmatively. 'Iliis adds ‘/M’ to the jel 
passed to MuiX’OM, which causes it to check for MACROS and MANIFESTS which have changed: if a 
FUNCTION uses a MACRO or MANIFEST which has changed, the FUNCTION will be listed as changed. 
MuiX'OM docs not normally check for this. 

'Extra JCL’ (Verbose): asked only if 'Compare with' is answered affirmatively. Whatever is supplied here will 
be passed to Mudcom as jel. before the files to compare. Iliis can be used to load macro files; see section 
8 . 1 . 

"Redo' (Verbose): asked only if a precompilation file was given. Takes a bunch of FUNCTION names, which 
will be recompiled. Note that the names supplied here will be appended to die list returned by Mudcom, 
if any, and that duplications in the list arc ignored. Sets REDO l -. 

'Package mode’ (Verbose): asked if a prceompilation file was given and Muixom was not run (Mudcom will 
set this if run). 'Iliis should be the name of a PACKAGE, which is assumed to be the PACKAGE being 
compiled. FUNCTION names in the ‘Redo’ list will be looked up in the appropriate PACKAGE OBLISTs if 
this flag is set, thereby saving some typing of trailers. Sets PACKAGE -MODE I -. 

Temporary file to’: 'Ilic compiler writes intermediate results to the temporary file, which is normally 

"sname'.jhamel >" (on ITS) 

”<siuwie> '.fjxame. TEMP" (on Tcncx/TOPS-20) 

You may change that by answering this question; there is rarely a good reason to do so. Sets 

TEMPNAMEI-. 

‘Source file to’: 'Ilic compiler can be caused to write out the assembler input it generates by answering this 
question. Assembler output normally goes to 


COMBAT 


5 2 



ITic Ml)l. Programming Hnvironmcnt 


87 


" stuv ne \f name I SOURCE" (Gnu'S) 

”<snaine> \fmme. SOURCE " (on Tcncx/TOPS-20) 

which is the default for tliis question; another name may be provided if desired. Sets SOURCE ! 

Special?’: The compiler normally assumes that variables which aren’t DECLed SPECIAL aren’t SPECIAL. If 
this flag is T (defaults to FALSE), all variables will be assumed to be SPECIAL unless declared otherwise. 
Sets SPECIAL!-. 

‘Expand floads?’: (Verbose) If true, F LOADS in the file being compiled will be expanded at load time. Sets 
EXPFLOAD! 

‘Expand splices?’: If true, objects of type SPLICE (PRIMTYPE LIST) will be expanded and inserted into the 
group. Sets EXPSPLICEI-. 

‘Careful?’: (Verbose) By default T, but if FALSE, the compiler will omit most of the bounds-chccking code it 
normally generates for NTHs, PUTs, and so on. Ihis obviously will make the compiled code run faster; it 
also makes debugging the compiled code nearly impossible. Sets CAREFUL 1 -. 

‘Reasonable?’: By default T, but if FALSE, the compiler will generate reasonable code only if everything you 
call from the functions being compiled is loaded into the compiler. SeLs REASONABLE 1 

‘Glue?’: By default T, but if FALSE, the compiler will not generate GLUE bits. There is no good reason to 
mv answer this. Sets GLUE l -. , 

‘Macro compile?’: By default FALSE, but if true, the compiler will compile MACROS. Sets 
MACRO-COMPILE I -. 

‘Macro flush?’: By default FALSE, but if true, MACROS which appear in the file being compiled will not 
appear in the NB I N. Sets MACRO- FLUSH!-. 

‘Max space?’: By default FALSE, but if true, the compiler flushes from core most of each RSUBR once it has 
been compiled; only the DECL is needed to help compile other functions. Ihis can, for compilations 
which arc very large, result in considerable improvements in speed. Sets MAX-SPACE ! -. 

‘First tilings to do’, ‘'filings to do’ (Verbose), and ‘Last things to do’: It frequently is necessary to perform 
some actions before a compilation can be run: definitions files must be loaded, special environment setup 
might have to be performed, and so on. All three of these questions arc designed to allow that: whatever 
you supply is put out after everything else in the plan but before the call to FCOMP. There are three 
questions, instead of one, to allow some things to be specified in a tailored compilation type, while others 
arc provided at compile time, or possibly from another tailored type. The three questions do not depend 
on each other; they arc asked in the order given here, and the answers appear in the plan in the same 
order. 


5.2.3. Requesting Compilations 

The first question asked by Combat is Type of compilation’. In addition to a number of special 
possibilities described later, there arc two answers to this question (in addition to any provided by the user 


5.2 


COMBAT 



88 


The Ml)l. Programming Hnvironment 


through the tailoring facility) which request pre-defined tailored compilation types. These arc ‘Verbose’ and 
‘Short’. 

‘Verbose’ causes all the normal questions to be asked: ‘New compiler?’, ‘Input file’, ‘Precompilation’, 
switches, ‘Things to do’, and so on. ‘Short’, on the other hand, defaults the answers to all questions except 
New compiler?’, ‘Input file’, and ‘How to run’. 

When requesting a compilation, one may type tQ at any time. This has the same immediate effect as an 
ESC, but in addition causes all questions between the one just answered and the ‘Tilings to do’ question to be 
defaulted. Tliis is particularly useful in the ‘Verbose’ sequence of questions. 

If ‘Many’ was given as ‘How to run’ for a previous compilation request, and the resulting plan has not yet 
been written out, subsequent plans will be appended to it. Using ‘Many’ will sometimes effect a major 
savings of time if several compilations wish to perform the same environmental setup; if they USE many of 
the same PACKAGES, for example. When using ‘Many’ in combination with predefined compilation types, it 
is useful to remember that whatever is specified under ‘Things to do’ may end up being performed for each 
plan. You might modify your compilation types to reflect this, or alternatively, edit the plan file produced by 
Combat to remove redundant operations. 

'rhe only way to get rid of the ‘Many’ plan is to answer ‘Many flush’ to the ‘Type’ question. Typing +S or 
answering ‘Abort’ to the ‘How to run’ question will abort the current portion of the ‘Many’ compilation, but 
not the whole thing. 

If ‘Many’ was mistakenly given as ‘How to run’, and you don’t wish to destroy the plan you have 
generated, it is possible to (in essence) go back to the ‘How to run’ question by answering ‘Many print’ for the 
compilation type. In this case, you arc not back in the plan-making loop; tR acts just like ts. 

tR, here, backs up to the last question asked. There are two qualifications. First, if tQ has been typed, 
then it backs up to the last question that would have been asked if tQ had not been typed. Second, the four 
questions ‘Precompilation’, ‘Compare’, ‘Redo’, and ‘Package mode’ arc treated as a group: if the ‘Package 
mode’ question has not yet been answered, it is possible to back up normally; but once that question has been 
answered, backing up to it will go to the first member of the group, ‘Precompilation’. 

tG allows one to obtain the answer to the current question from any user-defined compilation type. It 
requests a type name, and uses the answer or default supplied therein, printing the information so obtained. 
The tG must be typed as the first character of the answer for this to occur. Tliis allows one to use parts of a 


COMBAT 


5.2 



The M 131 - Programming Bnvironment 


89 


defined type without cither using the type itself or altering it for the occasion. For ‘Text’ type input (such as 
Things to do'), the string is placed in the input buffer but not completed, so it may be edited before an ESC is 
typed. See also the ‘Xerox type’ command. 

Note that there is a distinction made between ‘Compare’ and ‘Redo’; the former causes a Mudcom to be 
run, and the latter asks for the names of FUNCTIONS to be recompiled. It is possible to do both, in which case 
die two groups of FUNCTIONS are appended to fomi the ‘Redo’ list for the compilation. Note also that if a 
Mudcom has been run, the ‘Package mode' question will not be asked, since the answer is supplied by the 
Mudcom. Hither t R or t S may be used to kill a running Mudcom. 

One of the responses to the ‘How to run’ question is ‘Abort’, which returns directly to the ‘Type of 
compilation' question without writing out a plan, starting up a PCOMP, or anything else. Its effect is exactly 
that of a tS. In particular, if you arc making a long plan, only the portion just completed, not the entire 
compilation, will be aborted. 

It is also possible at the ‘How to run' question to supply an answer to any of the compilation questions 
(Input file, etc.). Hie ‘Question’ response asks for the name of a question, then asks that question. Any 
number of questions can be asked in this manner, one at a time. 'ITiis is particularly useful for filling in the 
blanks left by a ‘Short’ type compilation, or by user-defined compilation types. 

When a compilation request has been finished. Combat normally loops back to the ‘Type of compilation’ 
question, but changes the default from ‘Verbose’ to ‘None’ (meaning ‘Quit’), unless another compilation may 
reasonably be expected. Thus, one may leave by typing a single ESC. 

It is possible to modify Combat's behavior such that it either kills itself after finishing the compilation 
plan, or loops back with ‘Verbose’ as the default for the Type of compilation’ question. 

Comba t first decides whether a long compilation plan is being made; if so, the default remains ‘Verbose.’ 
If not, it then examines the current compilation type: if ‘Another compilation?’ has been set to ‘Yes’, the 
question will be asked with default ‘Verbose’; if it has been set to ‘No’, Combat' will kill itself; if to ‘Ask’, 
further consideration is required. 

If the user is in ‘Multiple’ mode (the ‘Multiple’ compilation type), the type of compilation will be asked 
with the ‘Verbose’ default Otherwise, Combat examines the state of two tailorablc switches, set by the 
‘Another compilation?* compilation type. If ‘Another compilation?’ has been set to ‘No’, Combat will die; if 
to ‘Yes’, the type question will be asked with default ‘Verbose’; if to ‘Ask’, the type question will be asked 


52 


COMBAT 



90 


Ihc MI)L Programming Environment 


with default ‘None’. Normally this is ‘Ask’. 

Note that ‘Another compilation?’ is like ‘Toggle verbosity' in that it will have no effect unless user-defined 
compilation types exist 

5.2.4. ’How to Run’ Options 

There arc four options available when answering the ‘How to Run’ question which determine where your 
plan file will be written and when the compilation it specifics will be run. 

‘Pcomp’ places die plan file on the <SNAME> directory, and names it "PCOMP >". Additionally, Combat 
will start a PCOMP (or NPCOMP, as appropriate) process if it is exited after writing a PCOMP file. ‘Pcomp’ is 
the standard method for running a compilation in one's own process. 

‘COMBAT’ writes die plan file to "COMBAT ; PLAN >". The COMBAT demon successively compiles all such 
plans at night, informing the persons who submitted them of the rcsulL 

‘Waste’ is like ‘COMBAT’, except that the plan is written to "COMBAT ; WASTE >". 'ITtc ‘waste’ queue is only 
run after midnight, which is usually sufficient for those who arc doing ‘overnight’ compilations. ‘Waste’ 
is the answer used by default for ‘How to Run’. 

‘File’ places die plan file on the <SNAME> directory, and names it "PLAN >”. This means that it will not 
be run until you explicitly load it into a compiler process. 

5.2.5. User Tailoring 

It is often the ease that a particular file is compiled quite often, or dial some sequence of actions must be 
performed as the ‘'Hungs to do’ before many compilations. Combat allows the user to define his own 
‘Compilation types’, each of which specifies exactly those questions which should be asked and the answers 
for those which should not. For example, one could have a type named ‘Ksign’, which says that the input file 
is always "SEND;ESIGN >" and in addition provides for the FLOAOing of two files in Things to do’. 
Further, since most questions arc defaulted, one might choose to answer only those questions which are 
interesting, such as ‘Prccompiladon’. It is also possible to supply a default answer for a question which will be 
asked. 

In addition, there arc some questions which arc not asked by the ‘Verbose’ compilation type, but which 

nevertheless arc available to user-defined types. 'Hicsc arc: ‘Macro compile’, ‘Macro flush’, ‘Max space’, 

» 

‘Fxpand splices’, “Special mode’, ‘Glue’, and others. 

One can select any of one’s own defined compilation types as an answer to the ‘Type of compilation’ 
question, just like ‘Verbose’ and ‘Short’. Except that the questions asked may differ, user-defined types are 


COMBAT 


5.2 



The MDL Programming Hnvironment ‘ 


91 


identical to the predefined types. 

5.2.5. 1 . Tailor files 

User-defined types arc saved (and loaded) from the file "s/;a/»c;%C0MBT TAILOR". It is possible to load 
other tailor files, but the "%C0MBT" file in sname is loaded during startup. Tailor files arc quite similar to 
Mdl GC-DUMPed files and thus cannot be edited other than with COMBAT. 

5. 2. 5. 2. Create type 

T his special compilation type requests a name for the type being made, then enters a loop with the prompt 
‘Question’. One may choose any of the available questions, and either supply an answer or (by default) 
request that the question be asked when a compilation of this type is being submitted. Note that only the 
‘Mow to run’ and the following ‘Type of compilation?’ questions will be asked unless others arc explicitly 
supplied; but one may supply answers to ‘How to run’ when creating a type. 

In this mode, tR will return to the ‘Question’ loop if one is about to supply an answer; otherwise, it returns 
to the Type of compilation’ loop, aborting the type creation. 

tG behaves exactly as it docs in the normal loop. To indicate that one is finished, one should answer ‘Finis’ 
to the ‘Question’ prompt. It is possible to supply several different versions of the answer to a particular 
question: the last one given will be used. One may wish to default a particular question, after specifying that 
it was to be asked or after supplying some different default. This may be done by answering ‘Delete question’ 
to the ‘Question’ prompt, whereupon one will be asked for a particular question to ignore. This question will 
then be completely ignored. Note that all interesting questions are initially in this state. 

There is also a ‘Set question default’ ‘Question’. This requests a question name, then asks the user to 
supply an answer. The question will be asked, with the default supplied. Thus default settings of switches can 
be changed, and one can supply a file name for the precompilation while still being asked whether 
precompilation is desired. Unfortunately, user-supplied defaults for ‘Text’-type questions arc used if ESC is 
answered; to get rid of the default, type SPACE ESC. Note that this is exactly the inverse of the convention 
for defaulting file names. 

When ‘Finis’ has been typed, a new copy of one’s tailor file is written out. This may, in combination with 
‘I .oad tailor’ and ‘Replace tailor', have undesirable side effects. 


5.2 


COMBAT 



92 


Tltc M 1)1. Programming Hnvironmcnt 


5. 2. 5. 3. Print type 

This requests the name of one of (lie types currently loaded, and prints out for it all questions which either 
will be asked when a compilation is being submitted or which have user-supplied defaults. If a particular 
question has been globally ‘turned off (such as the ‘New compiler?’ question, when there is no new compiler), 
an asterisk will be printed on the appropriate line to indicate that the information there is currently not used. 

5. 2. 5. 4. Delete type 

ITiis requests the name of one of the currently-loaded types, and deletes it. A new copy of the tailor file is 
written out, so all trace of the type will vanish when this command is used. 

5. 2. 5. 5. Alter type 

t his requests a type name, then becomes identical to ‘Create type’, except that some questions already 
have answers. Again, ‘Finis’ must be typed to leave the loop and cause die modifications to be filed; typing 
tR or tS will leave die loop, but the modifications will be forgotten. 

5. 2. 5. 6. Load tailor, Replace tailor 

Both of these request a file name, defaulting to die last one used for either a ‘Load tailor’ or ‘Replace tailor’ 
command. Initially this is "s;w/«e;%COMBT TAILOR". ‘Load tailor’ appends the types defined in the 
specified file to diosc already loaded, while ‘Replace tailor’ first throws away duisc already loaded. 'Hie types 
defined in this way arc not distinguished from those loaded from one’s own Combat tailor file; in particular, 
using ‘Toggle verbosity’ or any of ‘Create’, ‘Alter’, and ‘Delete type’ will cause all the types currently loaded to 
be written out to the Combat tailor file. If, dicrcforc, one has done a ‘Replace tailor’, one can easily lose all 
of one’s own types in this manner. I.c., it is very easy to destroy yourself. 

5. 2. 5. 7. Xerox tailor 

This requests the name of an existing user-defined type, and a new type name. The new type becomes an 
exact copy of the previously-existing type. This is particularly useful when one has several different types 
which do almost the same thing. 

5.3. The Compiler (Internals) 

'Ihc compiler’s job is to take a Ml)l. FUNCTION or group of FUNCTIONS and produce an operationally 
equivalent machine-language subroutine (RSUBR) using whatever information can be extracted from the 
source code and whatever additional information the user wishes to supply. 'ITic efficiency of the output code 
produced is directly proportional to the amount of information supplied by the programmer and inversely 


COMBAT 


5.2 



The MIJI. Programming Environment 


93 


proportional to the generality of the source program. 

'Hie information supplied by the programmer is usually in the form of optional data-type declarations 
(DECLs) and the use of programmer-defined data types (NEWTYPEs) that have built-in declarations. Unlike 
many programming languages, however, declarations arc never required. The compiler will compile 
programs with no declarations at all, but the resulting output will not run as fast as with well-declared code. 

The current compiler can achieve speed-up factors of anywhere from about 4 to 100. The factor of 4 
represents the speed-up fora very general program with very poor declarations. On the other hand, the factor 
of 100 represents a program with a very narrow range of application that has very good (that is, restrictive) 
declarations. Typical programs can expect to achieve factors of 20-40. 

5.3.1. How it Works 

The compiler as it currently exists is really two distinct programs. GETOROER is basically an interface 
between files of Mm. functions and the compiler. It is a relatively small program that reads in the file, sets up 
die various compiler switches, calls the compiler one or more times and writes out the final file of RSUBRs. 

COMPILE itself is basically a compiler with three major and three minor passes. Pass 1 builds a model of 
die program, pass 2 analyzes each node of the tree and docs data type analysis, pass 2.5 (minor) allocates stack 
space for variables and temporaries, pass 3 generates output code and two minor passes do final stack 
allocation and peep-hole opdmization. 

5.3. 1.1. COMPILE and COMPILE-GROUP 

There arc two distinct modes of compilation available. They arc simple and multiple. Simple compilation 
occurs when COMPILE is called with one FUNCTION. It simply compiles that FUNCTION and returns. 
Multiple compilation occurs when COMPILE is called with a list of FUNCTIONS. It compiles each FUNCTION 
into a separate RSUBR. It differs from multiple calls to COMPILE in that it sometimes partially compiles a 
FUNCTION out of order to determine its calling sequence and do argument type-checking. This behavior is 
necessary when compiling mutually recursive FUNCTIONS. 

In all modes of compilation, COMPILE-FUNCTION is called to actually compile the individual 
FUNCTIONS. It calls the various compiler passes. 


5.3 


The Compiler (Internals) 



94 


The Ml)l. Programming Hnvironment 


5.3.2. Modeling Pass 

Ihe first pass of the compiler takes the input FUNCTION and builds an expanded model of it. In the 
process of doing this, it produces a symbol table entry for every local variable bound and/or declared in the 
FUNCTION, any of its PROGs/REPEATs or MAPF/MAPR FUNCTIONS. It also produces die RSUBR DECL for 
die final output. Pass 1 also tries to decide if an internal entry (that is, an entry which can be called efficiently 
(see section 6.1)) can be used with this FUNCTION. If an internal entry turns out to be possible. Pass 1 
generates an appropriate calling sequence for internal calls to use. 

The model built by Pass 1 looks like the original FUNCTION with all of the nodes in the FUNCTION’S 
structure replaced with objects of type NODE (a new type defined for the compiler). A node in the model may 
have anywhere from 5 to 30 elements. The 5 element node is for simple quoted objects like fixed-point 
numbers, ATOMs etc. Ihe 30 element nodes are for major elements of the program such as the node for the 
FUNCTION itself and nodes for PROGs and REPEATS. Ihe majority of the nodes arc general SUBR nodes, 
which have 10 elements. 

Hie Pass 1 structure is built in the following way. The top level program in Pass 1 generates a node for the 
entire FUNCTION. 'Phis node gets the following information put into it 

1. A code specifying that this is a FUNCTION node. 

2. The data type that this FUNCTION is declared to return (or ANY). 

3. A LIST that will eventually contain the nodes comprising the body of the FUNCTION. 

4. A UVECTOR of internal names for internal calls to this FUNCTION. 

5. A symbol table for the variables declared and/or bound in this FUNCT ION. 

6. A list of entries in the symbol table specifying how the arguments arc to be set up (whether they 
arc optional, QUOTEd, TUPLE etc.). 

7. Ihe final RSUBR DECLs. 

8. A specification of how to pass arguments to this FUNCTION when it is compiled (whether the 
arguments should be in registers or on the stack). 

9. Ihe number of required arguments and the total number of possible arguments. 

In addition to the above information, slots exist in the node for additional information to be supplied by 
later compiler passes. 


Ihe Compiler (Internals) 


5.3 



The MDI. Programming Hnvironment 


95 


After the main node for the FUNCTION is built, the sub-nodes for the FORMs comprising the body of the 
FUNCTION arc built. This is done by first dispatching to special Pass 1 code for the first element of the FORM. 
If no special code exists for this first element, a dispatch is made on the TYPE of the first element of the FORM 
(that is, ATOM, FIX, FUNCTION etc.). If no special code exists for either the first element or its TYPE, a 
general FORM node is built In the ease of an ATOM as the first element of the FORM, the normal lookup rules 
arc invoked on the ATOM and it is dispatched again based on its value. ATOMS with no values either cause 
compilation warnings or arc assumed to be RSUBRs (depending on compiler switch REASONABLE). 

All FSUBRs (COND. AND, OR, FUNCTION, PROG, REPEAT, UNWIND, etc.) have special Pass 1 code and 
produce very specific nodes. Most SUBRs don’t dispatch to specific code during this pass. The exceptions arc 
things like MAPF, HIST, GET etc., which have somewhat non-standard treatment of their arguments. 
(Actually, MAPF and MAPR don’t treat their arguments non-standardly, but they arc treated specially in Pass 1 
so that the inner FUNCTION may be open compiled.) 

As mentioned previously, all nodes have at least 5 elements. Ihcsc arc as follows: 

1. A node type code. 

2. A pointer to the parent node (if one exists). 

3. A specification of the data type the node will generate. 

4. A list of sub-nodes referred to as kids, 

5. A name for the nixie, which may have different meanings for different nodes. 

In addition, nodes other than nodes for QUOTEd objects have additional elements that arc filled in during 
later passes of the compiler. 

After Pass 1 all additional passes work on the model built during Pass 1. The original FUNCTION is no 
longer even considered. 

5.3.3. Analysis Pass 

During Pass 1, very little information is determined regarding the resulting data types of various nodes. 
Indeed, with the exception of nodes prixluccd by quoted objects, structured objects which will produce code 
to build copies of themselves, and FUNCTIONS, PROGs and REPEATS with declared values, no type 
information is produced. Hven in the eases where type information is produced during Pass 1, it is usually not 
as detailed as other passes would like. The Analysis Pass has the job of refining the result type of each 


5.3 


The Compiler (Internals) 



% 


The Ml)l. Programming Fnvironment 


individual node based on various criteria 

1. 'ITic declared types of the variablcs.uscd in the program including GDECLsand MANIFESTS. 

2. Hie known type transfonnations produced by various SUBRs. (For example, it is known that 
LENGTH always produces a F IX result) 

3. Some analysis of the context of the nodes within the program. (For example in the following 
code: 

<COND ( <AND <TYPE? .X LIST) <NOT <EMPTY? .X»> 

<1 .X>)> 

regardless of how X is declared, it is obviously a LIST when the EMPTY? is run, and it obviously is 
not empty when the < 1 . X> is run.) 

'ITic Analysis Pass performs a standard depth-first lcfl-to-right tree walk on the Pass 1 model. The main 
dispatch function during this pass is called ANA. It docs an initial dispatch based on the node type of each 
node. Since most nodes arc still considered ‘SUBR nodes’, most of the dispatches end up at the SUBR call 
analyzer. The SUBR call analyzer has two types of further dispatch available. First it looks in a table for 
SUBRs that arc capable of being completely open-coded; if if finds an entry in the table, the analyzer for that 
SUBR is invoked. If this SUBR is incapable of being open-coded, ANA checks another table to see if this SUBR 
has an internal entry available. If it docs, the node is changed from a SUBR node to an internal SUB R node. If 
both dispatches fail, another table is checked to see if the object type returned by this SUBR is known, and if it 
is the result is put into the SUBR node. 

I 

Most of the work done by the Analysis Pass happens when the first dispatch occurs and special SUBR 
analyzers arc invoked. Generally speaking, these analyzers check to see if they know enough about their 
arguments to transform their nodes to an open-code specification. For example, an invocation of the SUBR 
REST only transforms to an open-code node if both the PRIMTYPE of the first argument is known at compile 
time and there are no SEGMENTS in the call to REST. If a special SUBR analyzer decides that it can’t 
open-compile in this ease, it either leaves the node as a SUBR node or transforms it to an internal SUBR node. 

5.3.4. The Type Analysis Model 

In addition to the model of the FUNCTION built in Pass 1, the Analysis Pass adds additional information to 
the model concerning the current states of local variables. As the analyzer plunges down into the tree, it tries 
to keep track of the current OECL of each variable. Specifically, there is a slot in each symbol table entry 
called CURRENT-TYPE. The analyzer updates that slot based on its current knowledge. A call to SET causes 
the CURRENT-TYPE slot to be changed to the analyzed type of SET’s second argument When multiple 

5J 


The Compiler (Internals) 



'ITic Ml)l. Programming Environment 


97 


control paths meet, the CURRENT -TYPE slots of a variable arc OR’d together at the joining point. 

t 

Conditional control structure nodes for COND, AND and OR also maintain two lists of transient information. 
These arc called TRUTH and UNTRUTH. They specify what information will be valid if the true or false 
branches arc taken respectively. For instance, a COND clause compilation can assume that any TRUTH 
information generated in the predicate of the COND will be valid for the rest of the clause. 

Some of the analyzers for the more widely used predicates have special code in them to add information to 
the current TRUTH and UNTRUTH values. Ilicsc predicates include TYPE?, EMPTY?, LENGTH? and NOT. 

Looping control structures pose additional problems for the type analysis model. The approach taken by 
the type analyzer is to build a copy of the current types of all variables before analyzing the loop structure. 
TTiis copy of the local type information constitutes the assumptions currently in effect. After the loop analysis 
is compete, the assumptions arc checked against the current state of the variables. If any of the assumptions 
have been violated, the assumptions arc updated and the loop is re-analyzed. 

5.3.5. Life-and-Death Analysis 

The Analysis Pass also performs a lifc-and-dcath analysis on the local variables. This is done by assuming 
that the variable’s value is dead at each LVAL node for that variable. If another LVAL node for this variable is 
discovered that is reachable from this one before any intervening SET nodes for this variable, the original 
node is updated to be alive. This life-and-dcath information is used during the Code Generation Pass. 

5.3.6. The Variable Allocation Pass 

ITic Variable Allocation Pass (VAP) is a relatively simple one. Its purpose is to allocate stack space for all 
of the variables bound in the FUNCTION, its PROGs and REPEATS and its MAPF/MAPR FUNCTIONS. There 
are various switches that control the manner in which this allocation is performed. 

The most important switch specifics whether or not this FUNCTION needs a FRAME or not. The VAP 
always starts out assuming it docs not need to build a FRAME. This assumption will be changed if it is 
discovered that cxterrially accessible named ACTIVATIONS exist in the FUNCTION or any of its inner blocks 
(PROGs or REPEATS or FUNCTIONS) or if at any time it is discovered that the address of a variable cannot be 
specified as a fixed offset from the top of the stack. Whenever this assumption is changed, the VAP starts 
over again with the new assumption in affect 

Another switch that controls the behavior of the VAP specifies whether or not the stack slots for inner 


5.3 


The Compiler (Internals) 



98 


'|-hc M 1)1. Programming Environment 


blocks will be prc-allocatcd because the stack will be in a ‘fuzzy' state when these blocks arc running. The 
stack is said to be in a ‘fuzzy’ state when the number of slots currently being used cannot be determined at 
compile time. This usually occurs when a TUPLE is being constructed for a MAPF. For instance, in 
<DEFINE F (X Z) 

<MAPF .VECTOR ^FUNCTION (Y) < = = ? .Y ,Z» .X>> 
the elements of tlic VECTOR will be between the top of the stack and the location of variable Z. Even if F has 
a FRAME, the location of Y will not be known relative to the FRAME pointer at compile time. TTicrcfore, the 
initialization code for F will prc-allocatc the stack space for Y. 

During the VAP, each symbol table entry gets its address field set based on where that variable will be on 
the stack. Also nodes for PROGs, REPEATS and MAPF/MAPR FUNCTIONS that have bound variables get 
additional information inserted in themselves. This information includes where the SPECIAL variables start 
and where the UNSPEC I AL variables start 

5.3.7. The Code Generation Pass 

'Fhc Code Generation Pass (CGP) is probably the most complicated of all the passes. Fortunately, the 
Analysis Pass has already refined the model so that the CGP can dispatch immediately to the special-purpose 
code generators. Besides building a list of assembly-language instructions as output, the CGP keeps track of 
the current state of the stack, the contents of the registers, the current state of variables (whether they arc in 
registers or on the suck or both) and the contents of the temporaries. 

[lie general dispatch routine during the CGP is called GEN. It takes two arguments: A NODE and a 
specification of where to leave the result. The second argument can be any of the following: 

1. The ATOM FLUSHED, meaning that the code will be executed for effect rather than value. 

2. ITic ATOM DONT-CARE, meaning that the caller of GEN is leaving the decision up to die specific 
generator as to where to leave the result 

3. An object of type DATUM which specifics a place for the type and value of the result to be left. 

Type DATUM is of PRIMTYPE LIST and contains two elements, one for the type and the other for the 
value. The elements of a DATUM may take on a variety of values in different circumstances. 'ITicsc include: 

1. A TYPE name. This can only occur in the type slot and it means that the type of the object is 
known at compile time and this is it. It indicates that the code generator need not put the 
type-code anywhere. 

2. The ATOM DONT-CARE. This means that the caller doesn’t care where the result for this field is 


The Compiler (Internals) 


5.3 



The Ml)l. Programming Environment 


99 


left. 

3. The ATOM ANY-AC. 'ITiis tells the generator to leave the result in any available AC. 

4. An object of type AC. 'ITiis tells the generator to force the result into a specific AC. 

5. An object of type ADDRESS :C or ADDRESS : PAIR. Both of these specify addresses on the stack 
or in the interpreter. 

6. An object of type OFFPTR. An OFFPTR has three fields: a DATUM, an offset (a FIX), and a 
PRIMTYPE. An OFFPTR tells the generator to leave the result in the word pointed to by the inner 
DATUM and offset by the offset. 

If an element of a DATUM is ANY-AC or DONT-CARE, the generator is required to update the DATUM to 
reflect the actual location of the result. If the element is a TYPE, the generator may change it to an AC which 
means that it happened to end up with the TYPE in that AC. 

The generators always return a DATUM specifying where the result was actually left, unless the caller 
wanted the result FLUSHED. ’Ilicrc is one special DATUM that can be returned. It is the GVAL of the ATOM 
NO-DATUM and it means that the specified node will not return a value (that is, it is a RETURN or an AGAIN or 
something). 

There are six objects of type AC in the compiler, corresponding to ACs 0, A, B, C, D and R AC 0 is special 
since it can’t be used as a pointer, and it always contains very transient information. It is never used to fill in 
an ANY-AC slot in a DATUM. The other five ACs arc in the pool of available ACs. Objects of type AC have 
about ten different slots associated with them. 'ITicy arc used for finding available ACs and generating output 
code that uses them. The slots used in AC allocation are as follows: 

1. ACLINK. If this is FALSE, the AC contains no temporary value for the current computation. 
Otherwise, it is a list of active DATUMs that contain it 

2. ACAGE. This is only used when the ACLINK is non-FALSE. It is updated to a higher number at 
each use of the AC and is used in an LRU algorithm when an active AC must be flushed. 

3. ACRESIDUE. If this AC is currently equivalent to some local variables, this slot contains a list of 
the symbol-table entries for these variables. The symbol-table entries themselves have a slot 
called INACS that points back to the ACs that contain its type and/or value. They also contain a 
slot called STORED that specifics whether the only copy of the variable is in tlic ACs or it is also in 
memory. 

4. ACPROT. This slot is a boolean saying whether this AC is protected or not. If the AC is protected, it 
can’t be allocated for any reason. Protection is only invoked for very stretches of code. 


5.3 


The Compiler (Internals) 



100 


The M I )l, Programming Knvironment 


5. ACPREF. This slot says that this AC deserves slightly preferential treatment. It means, all other 
things equal, don’t choose this AC. 

f 

The AC allocation algorithm consists primarily of trying to find the best possible candidate when an AC is 
needed. The routine GETREG is used to find an available AC. First it rejects all ACs that arc protected (if they 
all arc protected, the compiler generates an internal error since this should never happen). If there arc one or 
more ACs with their ACLINKs FALSE, GETREG will choose from among them. It will prefer ACs with no 
ACRESIDUE. that arc numerically adjacent to another free AC (because some PDP-10 instructions destroy the 
next AC), and which do not have their ACPREFs on. If the AC chosen has an ACRESIDUE, code is generated 
if necessary to store any of the variables that arc only in ACs. 

If no AC exists with an ACLINK that is FALSE, GETREG finds the AC with the smallest ACAGE. Code is 
generated to store the contents of the AC in a temporary so that it is available. The DATUMs that were in the 
ACLINK arc updated to indicate that they arc now pointing to temporaries as opposed to ACs. 'Ihus it is 
possible that a generator could need sub-results in ACs, and after causing one to be generated in an AC, find 
that while generating the second one the first slipped back into a temporary. Hie generator would then have 
to generate code to reload an AC from the temporary. 

The CGP invokes various special-case optimizations by passing information up and down the tree as code 
is generated, 'flic generators for conditional branching FSUBRs like OR, AND and COND employ a predicate 
generator whenever possible. This generator is like GEN except that it takes three additional arguments: a 
label to branch to, a flag saying whether to branch on truth or falseness, and a flag saying whether this 
predicate is being NOTed. 'I he general predicate generator then looks at die predicate node to see if it can 
take the additional arguments for predicate generation. If it can, the general predicate generator just passes all 
the arguments down; otherwise it calls GEN and generates the additional testing and branching code itself. 
Currently AND, OR, COND, ==?, N==?, G?, G=?, L?, L=?, 0?, 1?, TYPE?, NOT, ASSIGNED?, MEMQ, 
LENGTH? and EMPTY? have special predicate code associated with their generators. Others may be added as 
the need develops. 

Other optimizations arc invoked by simply recognizing common patterns of Mdi. code. For instance, the 
compiler recognizes <SET X <+ .X 1>> as a PDP-10 AOS instruction and it generates very efficient code 
for<REST .X <- <LENGTH .X> 1>> by recognizing the pattern of code. 

The compiler always takes advantage of as much knowledge as it has about the types generated by 
particular nodes to generate good code. This is especially the ease when it is handling the code for NTH, REST 
and PUT in structures. It uses type information concerning the length of the structure and the amount being 


The Compiler (Internals) 


5.3 



The MI)I. Programming Hnvironment 


101 


RESTed for the NTH, REST or PUT, to figure out whether or not to generate bounds checks in the compiled 
code. It also uses information about the current type of the slot being read or written to decide whether not to 
read or write the type word. Obviously, a lot of this type information was the same information obtained 
during the Analysis Pass of the compilation. 

Some code generation routines arc capable of changing the order of generation of the sub-nodes. This is 
done to try to get the node requiring the most ACs compiled first so that it won’t interfere with any AC 
requirements of the current node. 'ITiis obviously requires that the commuted nodes have no interacting side 
effects. 


5.3 


The Compiler (Internals) 



102 


'ITic Ml)l. Programming Hnvironmcnt 


6.0 



The MDL Programming Environment 


103 


6. Making It Run Faster 

Once you have a working program, you will probably want it to run fast. ITic most obvious way of doing 
this is to compile it. Mdl provides other ways to speed up code, chiefly by eliminating mediated subroutine 
calls, and by reducing the size of garbage-collected space. 

Mediated subroutine calls (or ‘MCALLs’) arc the standard method of function calling in Mdl. They 
provide a great deal of information and control during program development and debugging, but the 
overhead of an MCALL is superfluous in debugged production programs. Consequently, several methods exist 
for removing this overhead. 

A subtle impediment to increased speed in a production program is the amount of time devoted to garbage 
collection. As this is proportional to the size of the garbage collected space, it is advantageous to make that 
space as small as possible. One way to do this is to purify as many of the static data structures in the Mdl as 
possible. 

One by-product of the procedures mentioned above is that much of the resulting code and structure 
becomes pure and therefore shareable between many Mdl processes. 

6.1. GLUE 

A facility exists to allow separately compiled and assembled RSUBRs to be ‘glued’ together, 'lTiis makes 
calls between RSUBRs in the group much faster, as MCALLs are replaced by PUSHJs. The many instructions 
of an MCALL are replaced by the single PUSHJ, but the mediation provided by MCALL is lost: No FRAME is 
produced. GLUEing is accomplished by the concatcntation of the code and reference VECTORS of the RSUBRs 
being GLUEd, which gives them a common ‘frame of reference.’ 

Additionally, GLUE is interfaced with the compiler such that: 

1. The RSUBRs can be run unGLUEd for convenient tracing and debugging. After debugging, they 
can be GLUEd together and run much fester. 

2. An individual FUNCTION can be recompiled without the overhead of recompiling everything 
GLUEd to its RSUBR. After the recompilation, the entire set can be reGLUEd. 

6.1.1. How to Glue 

"GLUE " is a PACKAGE and it may be obtained by doing 


6.0 



104 


Ihc Ml)l. Programming Hnvironmcnt 


<USE "GLUE"> 

The call to glue a group ofRSUBRs and/or RSUBR-ENTRYs is: 

<GR0UP-GLUE crouo-name:atom 
substitute: boolean 
scriplxhanne! 

package: string-or list 

survivors: list 


where: 

group-name is an ATOM as returned by GROUP-LOAD, and it is the only required argument 

substitute is a flag; if it is true, the current RSUBRsand RSUBR-ENTRYs will be fixed so that they may still run 
in the current Mot.. ’litis is expensive but necessary if PRINTTYPEsor interrupt handlers arc among the 
RSUBRs in the group. If the flag is FALSE or not supplied, the group must be GROUP-DUMPed and 
reloaded before use. 

script if supplied and a CHANNEL is used by GROUP-GLUE to print out its progress through its task. 
Otherwise, GROUP-GLUE works silently. 

package , if provided and non-FALSE, implies PACKAGE mode will be used, litis argument should be a 
STRING specifying the PACKAGE that is being glued. In PACKAGE mode only the ENTRYs of that 
PACKAGE will be preserved and all RSUBR-ENTRYs associated with internal functions will be removed, 
'litis option can also oc used by setting the ATOM PKG to the name of the PACKAGE. Package may also be 
a LIST of PACKAGE names, in which ease the ENTRYs of all the PACKAGES listed will be preserved. 

survivors if provided indicates that SURVIVOR mode will be used. This argument should be a list of those 
RSUBR-ENTRYs to be preserved. All other RSUBR-ENTRYs will be flushed. Tltis option overrides 
PACKAGE mode. This option can also be used by setting the ATOM SURV to the LIST of RSUBR-ENTRYs 
being preserved. 

victims allows ‘survivors’ to be specified by default; that is, it is a LIST of those functions which should not 
survive after GLUE has run. 'ITiis is sometimes more convenient to specify than explicit survivors. 

There arc two advantages to removing unneeded RSUBR-ENTRYs. The group is made smaller by the absence 
of the RSUBR-ENTRYs. Also the code for the group is reduced, as the code for handling MCALLs to those 
RSUBR-ENTRYs is removed. In general only the ENTRYs need to be kept for a PACKAGE. This can be done 
by specifying the PACKAGE using PACKAGE mode. SURVIVOR mode should be used if the user wishes to 
explicitly state which RSUBR-ENTRYs arc to be kept 


6.1.2. GLUE as a Program 

In addition to the "GLUE " PACKAGE, there is a program in which GLUE and PDUMP (see section 6.3) are 
prcloadcd. It will prompt for each of the usual arguments to GROUP -GLUE, permitting the user to 
conveniently GLUE (and PDUMP) several PACKAGES in one session. 


GLUE 


6.1 



The Mill. Programming Knvironment 


105 


6.2. Glue Bits 

GLUE is able to perform its transformations on compiled or assembled code with the aid of a data structure 
produced during assembly. This structure is called the ‘GLUE Bits’. It is an association placed on the RSUBR 
by this FORM: 

<AND <ASSIGNED? GLUE> 

.GLUE 

<PUT rsubr GLUE glue-bits:uveclor > > 

Thus if . GLUE is non-FALSE the association will be available to programs wishing to use it 

Internally, the GLUE bits consist of two bits for each word of code in the CODE element of the RSUBR, 
followed by words specifying calling information. For each INTERNAL-ENTRY in the code, there is a word 
giving the number of arguments it lakes and the offset of the INTERNAL-ENTRY in the CODE UVECTOR. 

'Ihc two bits for individual instructions arc interpreted with die index field of die instruction 9 s follows: 

Bits 0 implies the instruction is uninteresting; 

Index field ( M) and bits 1 implies the instruction is a reference to the code itself (a jump, perhaps); 

Index field (R) and bits 1 implies a reference to an impure slot of the RVECTOR (the compiler docs not 
generate such references); 

Index field ( R) and bits 2 implies the instruction is an MCALL; 

Index field ( R) and bits 3 implies the instruction is a reference to a pure slot of the RVECTOR. 

See section 7 for more details on the format of MDL Assembly code. 

6.3. PDUMP 

Mdl provides a mechanism for sharing compiled programs among several Mm. processes, and for 
dynamically moving the compiled code in and out of the virtual address space as space is needed in the 
interpreter. 'Ihis mechanism is described in detail in section 4.2. Ihis section describes how to convert a 
compiled program into a sharablc version, known as an FBIN (Fast-BINary) version of the program. 

First load the group-purifier. 


6.2 


Glue Bits 



106 


'Hie MIX. Programming Hnvironmcnt 


<USE "PDUMP"> 

Next, GROUP-LOAD your group (or groups). 

<G ROUP- LOAD binary file:strine > 

which returns the group-name of the group. This (and any other groups to be dumped together) is then 
passed to the pure-dumper: 

<PDUMP croun-namel.atom group-name2:atom ... > 

This creates several files, only one of which you need be concerned with: 
sname ; group- name! F B I N 

If given more than one group- name, PDUMP will create one FBIN file for each group, but only a single FIXUP 
and a single SAV file containing the fixups and code for all of the groups named. The FIXUP and SAV files 
arc put on the "MUDTMP" directory and eventually are inserted in the pure code library, as described in 
section 4.2. 

Alternative methods of PDUHPing arc to specify that as an option in to the program GLUE (sec section 
6.1 .2), or to use its preloadcd PDUMP directly after exiting its READER with tS. 

A warning about combining GLUE and PDUMP: if you attempt to PDUMP several groups that have been 
GLUEd together, you will lose. This is because the references to the ‘group-RSUBR’ will fall on the wron* 
OBLISTs. 

PDUMP also produces a structure analogous to the GLUE bits (sec section 6.2) produced by the compiler, 
but containing only information about the RVECTOR of the RSUBR, for the use of PURIFY (sec section 6.5). 

6.4. SUBRFY 

SUBRification is a way of getting rid of many of the MCALLs which could not be practically removed using 
GLUE. If a FUNCTION is called by many separate groups, it is difficult to GLUE it to all the groups or to GLUE 
all die groups together. 

What is really needed is to be able to allow something to be catted with PUSHJ from separate groups 
without forcing it to be part of those groups. This is indeed the case with PUSHJ entries to Mot. SUBRs (in 
the interpreter). A user can make his RSUBRs look like SUBRs in this respect 

SUBRFY takes a group, which must be in MB IN format It purifies the RSUBRs and RSUBR- ENT RYs in the 
group and changes them so that they can be called with PUSHJ. It also produces a file, known as the ‘preload’ 
file, which can be used by the compiler to generate PUSHJs to the functions in the SUBRificd group. 


PDUMP 


6J 



The MDL Programming Knvironment 


107 


SUBRFY should be loaded before loading the group to be processed. The reason for this is that it 
guarantees that GLUE bits stay around. To load SUBRFY 
<USE "SUBRFY"> 

You should then GROUP-LOAD the group. Your group should be GLUEd already, since SUBRFY does not 
GLUE the group together. 

SUBRFY can then be called in the following manner: 

<SUBRFY eroup:alom 

file- name: string 
out pul: channel 

where 

group is the name of the group. 

file-name is the name of the file in which SUBRFY should put the information for the compiler. This defaults 
to the name of the input file with second name "PRELOD". 

output is an optional argument which specifics a CHANNEL on which to print information about SUBRFY’s 
progress. 'ITic default is not to print anything. 

Hie file produced by SUBRFY should be FLOADed for compilations where functions in the SUBRified group 
arc called. This can be done by F LOADing it in the ‘Ihings to do’ part of a combat plan. 

I.ike purification, SUBRification changes the MDL. The only way to preserve the SUBRified group is to 
SAVE the Mdl. Before SAVEing the MDL the "SUBRFY" PACKAGE should be removed. 'This can be done 
by doing a 

<KILL-SUBRFY> 
followed by a 

<GC 0 T>. 

SUBRFYing a group implies that the group is not going to change at all frequently, if ever. A new 
SUBRFYed SAVE file may be created at any time, and elements of the group may be recompiled. However, if 
the calling sequences of any of the functions in that group change, you invalidate any functions compiled 
using the ‘preload’ file for that group. In short, think twice before tying yourself down with SUBRFY. 

6.5. Purification 

A facility exists to permit the purification of Mix. objects. Purified objects can be shared between Mdl 
processes and also arc not examined by the garbage collector. What follows is a description of how this 
facility can be used. 


6.4 


SUBRFY 



108 


The MDL Programming Knvironment 


'Hie purification facility in Mdl is most useful in the creation of subsystems. Non-purified RVECTORs of 
RSUBRs and tables used by subsystems arc kept in garbage collected space. This means that these objects, 
which will never become garbage, are examined at each garbage collection, slowing down the garbage 
collection process. Also, if two people are using the same subsystem, they cannot share the tables and RSUBRs 
kept in garbage collected space. By using purification these two problems can be alleviated. 

To purify most objects the user can call the PURIFY SUBR. 'Hie object will be purified, and all references 
to that object in the Ml)l. core image will be changed to point to the new pure object. This simple method 
cannot be used in the ease of RSUBRs. Purification of RSUBRs is a several step process beginning with 
compilation. 

6.5.1. Purifying RSUBRs 

Once your FBIN or NBIN is ready you can actually do purification. To do this first 
<USE "PURITY"> 

This PACKAGE contains the routines needed to purify RSUBRs. Then GROUP-LOAD the files you wish to 
have purified. Once this is done type 

<GROUP-PURIFY arom: atom outpul:channel> 

This will purify and link all RSUBRs and RSUBR-ENTRYs in the group and will also attempt to purify any 
RSUBRs or RSUBR-ENTRYs called by the group. Giving the optional channel will cause GROUP-PURIFY to 
print information concerning the progress of the purification. 

GROUP-PURIFY will only purify RSUBRs and RSUBR-ENTRYs. In order to purify tables, etc. use the 
PURIFY SUBR directly. Since purification is an extremely expensive operation, it is recommended that you 
collect together the things you wish to purify into a L 1ST, VECTOR, etc. and purify that structured object. 

Once purification has occurred, several things may be done to recover wasted garbage collected space. 
The user can get rid of the "PURITY" PACKAGE by doinga 
<KILL:PURITY> 

'ITie user can also remove much of the overhead of keeping a group around by UNASS IGNing the 
group-name. Removals of this type should be follwed by an explicit call to the garbage collector invoking the 
‘hairy’ GC feature, as much of the storage to be regained is pointed to by associations. ITiis can be done by 

<GC 0 T> 

In order to save a file with purified Mdl objects you must SAVE. Restoring a SAVEd file with purified Mdl 
objects will cause those objects to share with any other Mdl RESTOREd from the same SAVE file. 


Purification 


6.5 



'ITic MDL Programming Knvironmcnt ' 


109 


6.5.2. Purifying an Environment 

Many subsystems maintain a list containing pointers to all the static data structures built by that 

f 

subsystem: dispatch tables, data bases, and so on. The list can be given to PURIFY to move all its components 
into the pure area. However, there arc other structures in garbage collected space that may be purified; e.g., 
the RVECTORs of RSUBRs, RSUBR DECLs, and soon. 

The "CLEAN" PACKAGE examines these structures, looking for diosc which may be purified. It may also 
be used for informational purposes. To get it 
<USE "CLEAN"> 

"CLEAN" has one major ENTRY, CLEANUP, which examines every ATOM of every OBLIST in die MDL It 

may perform a variety of functions, but it is most often used to make DEC Ls share storage and to accumulate a 

LIST of purifiablc structures. All of its arguments arc optional. 

<CLEANUP print?: boolean 
reset?: Iwolean 
decl?:boolean 
gdecl?: boolean 

purc?:boo!ean 

check?:boolean 

avoid:list-of-oblisls> 

print? is by default FALSE. If non-FALSE, information about each ATOM examined will be printed as 
CLEANUP runs. This is a lot of informadon. 

reset? is by default T. If non-FALSE, the LISTS of objects previously collected will be reset before CLEANUP 
runs. 

dec!? is by default T. If non-FALSE, each DECL element will be made to exist exactly once in the entire core 
image. K.g., dicre will be only one copy ofthcDECL <LIST [REST F IX] > in the core image. 

gdecl ? is by default T. It is similar to decl?, but refers to G DECLs. 

pure? tells whether to make a LIST of all die purifiablc objects in the core image. It is by default T. 

check? tells whether to make LISTS of all the TYPEs, RSUBRs, RSUBR-ENTRYs, etc. in the core image. It is 
by default T. 

avoid is a LIST of OBLISTs not to look in; it is by default the OBLISTs associated with "CLEAN" and 
"PURITY". 

CLEANUP returns (if pure ? is non-FALSE) a structure (also stored as the GVAL of PURELST) which may be 
given to PURIFY. 

The results of running CLEANUP may be examined by 


6.5 


Purification 



no 


The M 1)1 Programming Knvironment 


<PRINT-CLEANUP> 

As the object in running CLEANUP is to shrink the size of one’s MDL and its garbage-collected space, it is 
useful to be able to remove CLEAN after it has done its work. 

<FLUSH-CLEANUP> 

removes everything associated with the PACKAGE from the Mdl. 


6.5.3. Purification Summary 

In a simple case, one can purify a 'subsystem' of one group maximally by 

<USE "PURITY" "CLEAN"> 

<GROUP-LOAD "/oo"> 

<CLEANUP> 

<GROUP-PURIFY foo> 

<KILL :PURITY> 

<FLUSH-CLEANUP> 

<GC 0 T> 

<SAVE ”foo”> 


6.6. TEMPLATES 

The PRIMTYPE TEMPLATE cuts down on the need for storage by allowing the user to specify exactly what 
he wants a structured object to contain, similar to ‘structures’ in PI 71 or C. 

To use this feature one must create a new TYPE of PRIMTYPE TEMPLATE. This can be accomplished by 
using the RSUBR TEMPLATE. The procedure for doing so is: 

<USE "TEMPLATE "> 

<TEMPLATE name: atom ... specs ... > 

where name is the name of the new TYPE and specs arc specifications for each element of the TEMPLATE. 
This returns the TYPE name of the TEMPLATE and creates a creator of TEMPLATES of TYPE name , called 
name itself, which can be applied to arguments to create objects of that TYPE of TEMPLATE. 

The specification for the elements can be of several forms. It can be one of 

a TYPE: type:atom 

a2-clcmcntLIST: (type: atom length: fix) 
a 3-clcmcnt LIST: (lype.’atom length:fix count:fix) 

Below arc some examples along with explanations: 


Purification 


6.S 



The MI)L Programming Hnvironment 


111 


LIST 

is an 18 bit LIST pointer. 

(FIX 18) ' 

is a halfword FIX (can be both positive and negative and is checked for overflow). 

(FLOAT 18) 

is an 18 bit FLOAT (which is the left halfword of a ‘normal’ TLOAT and therefore somewhat restricts the 
precision). 

(FIX n) 

(where n is less titan 18) js a positive FIX of length n bits (is not checked for overflow). 

BOOLEAN 

is not a Ml)l. TYPE, but a one bit FALSE or non-FALSE depending on whether die bit is 0 or 1. 

(UVECTOR 18 n ) 

is an 18 bit UVECTOR pointer. Hie UVECTOR is of length n. The same can be done for VECTORS. 

(STRING 36 n ) 

is a 36 bit string byte pointer. The STRING is of length n. 

ANY 

is not a Mdi, TYPE, rather anything can go here. This is relatively inefficient to use in TEMPLATES as it takes 
up 2 words. 

In order to provide more flexibility in using TEMPLATES, two other fields arc allowed, an optional field 
and a rest field, lhc optional field allows the user to create TEMPLATE TYPES which will have die same basic 
structure but which can have optional elements determined when the actual TEMPLATE is created. The rest 
field, like the optional field, allows elements to be optional but specifics a pattern for any elements diat are 
added on. It is analogous to REST in DECLs. Separation of fields is accomplished by the use of the strings 
"REST" and "OPTIONAL". For example: 

<TEMPLATE F00 FIX "OPTIONAL" LIST BOOLEAN "REST" FLOAT> 

This creates a TYPE FOO of PRIMTYPE TEMPLATE which always has a FIX as the first element, can have a 
LI ST as a second element, can have a one bit T or 0FALSE ( ) as the diird element and can have any number 
of FLOATS from the fourth element on. 

6.6.1. Use of TEMPLATES 

TEMPLATE TYPEs may be thought of as primitive TYPEs, in diat they each have a unique storage 
representation. On the other hand, the TYPEPRIM of any TEMPLATE TYPE is TEMPLATE. A primitive 
TEMPLATE (which cannot truly exist in the language) would look like 


6.6 


TEMPLATES 



112 


The Mill. Programming Knvironment 


{ element- 1 element- 2 ... element- n } 

Real TEMPLATE TYPES arc represented as NEWTYPEs of this primitive TEMPLATE TYPE. 

# type- name { . . . elements . . . } 

This method is similar to the usual method in Mdl for representing any new TYPE, in that a RESTcd 
TEMPLATE will be printed ‘CHTYPEd to its PRIMTYPE.’ Note that a TEMPLATE so printed cannot be read by 
READ: a'primitivc TEMPLATE’ cannot exist It is best to avoid printing RESTcd TEMPLATES. 


Below are some examples of the use of TEMPLATES. 

TEMPLATE BAR 
FIX 

"OPTIONAL" BOOLEAN 

"REST" (FIX 18) (FLOAT 18)>S 


<BAR 1>$ 

«BAR {1} 

<BAR 1 T>$ 

#BAR {1 T) 

<BAR 1 <> 1 1.0>$ 

#BAR (1 #FALSE () 1 1.0} 

<SET A <BAR 1 <> 1 1.9 2»$ 

#BAR (1 f FALSE () 1 1.898437S 2} 

<PUT .A 1 8>$ 

#BAR {0 *FALSE () 1 1.8984376 2} 

<PUT .A 4 1.999 >$ 

#BAR {6 fFALSE () 1 1.9960937 2} 

<TEMPLATE BAR (STRING 36 4) "REST" AMY>$ 
fFALSE ("ALREADY A TEMPLATE") 

TEMPLATE BARI (STRING 38 4) "REST" ANY>$ 
BARI 


TRMPlATEs 


6.6 



The MDL Programming (Environment 


113 


<SET A <BAR1 "HELP" 2 () <>»$ 

#BAR1 {"HELP" 2 () #FALSE ()} 

<PUT .A 1 "G00D">$ 

#BAR1 {"GOOD" 2 () #FALSE ()} 

<PUT .A 1 "GOOD-BYE">$ 

•ERROR* 

TEMPLATE -TYPE- VIOLATION 
PUT 

LISTENING-AT-LEVEL 2 PROCESS 1 

6.6.2. Assembly of TEMPLATES 

Once a scl of TEMPLATE TYPEs is created, as for the TYPE definitions of a subsystem, it saves time to 
store away the ‘compiled' TEMPLATE generators and not recreate them each time the definitions arc to be 
used. 

The "TEMHAK" PACKAGE modifies files which define TEMPLATE TYPES to contain the TEMPLATE 
descriptions and RSUBRs rather than the calls to TEMPLATE. It is only useful, of course, when the 
TEMPLATES arc defined in a file which will not normally be edited, since the new files arc in 'NB IN’ format. 
To load this PACKAGE, 

<USE " T EMHAK " > 

The PACKAGE has two entries. 

<TEMPLATE-DUMP erouD-name:atoni > 

takes the group and modifies it such that <USE "TEMPLATES becomes <USE "TEMHLP">, and all 
top-level invocations of TEMPLATE arc rcphiccd by calls to BUILD-TEMPLATE (for the TEMPLATE 
descriptions), SETGs of the TEMPLATE-gcncrating RSUBRs, and the GLUE bits for the RSUBRs. 
<FILE-TEMPLATE inout.strine output :string> 

takes an input file and performs the same service, GROUP-DUMPing the result to the optional output file (by 
default the same file with second name "NBIN"). This is useful for files which contain nothing but TYPE 
definitions, a common practice in large subsystems. 

If the TEMPLATE TYPEs arc defined in a file which will be edited frequently, a different set of routines is 
used after creating the TEMPLATE TYPEs: 


6.6 


THMPLATEs 



114 


The Ml)l. Programming Environment 


<DUMP-TEMPLATES descriotions:slrine > 

places tlic TEMPLATE descriptions (not the RSUBRs) in the specified descriptions file. It docs so for all 
TEMPLATE TYPEscurrcntly defined. 

<DUMP-RSUBRS nubrs.'slrina template- tvpe:atom ... > 
will perform the same service for the TEMPLATE-gcncrating RSUBRs of the TYPES given as the second and 
later arguments to DUMP-RSUBRS. 

r ITicrc will now be two files, one containing the TEMPLATE descriptions and the other the RSUBRs. These 
may now be used to create the TEMPLATE TYPES without USEing "TEMPLATE". To do so: 

<USE "TEMHLP"> 

This defines the RSUBRs needed to Like the TEMPLATE descriptions and make them useful to Mdl. 

< F LOAD descriptions:string> 

the file of descriptions (the file created with DUMP-TEMPLATES): this must be loaded before die RSUBRs 
file. Then load die RSUBRs file (the file created by DUMP-RSUBRS): 

< F LOAD rsubrs: string> 

For maximum convenience, it may be necessary to put a FORM in files that create TEMPLATES: if the 
TEMPLATE files described here exist, FLOAD them; otherwise, <USE "TEMPLATE "> and create the 
TEMPLATES from scratch. It is of course possible to manually merge the two TEMPLATE definition files 
(preferably by using GROUP-LOAD and GROUP-DUMP), so long as the TEMPLATE descriptions precede the 
TEMPLATE RSUBRs. 

TEMPLATE RSUBRs arc created with GLUE bits, so it is possible to glue them into groups and to purify 
them. 


TF.M PLATEs 


6.6 



The MDI. Programming Hnvironment 


115 


7. The Assembler 

It is occasionally necessary to write Mdl routines in assembly language, usually to interface with a feature 
of the operating system not available in the interpreter. The Mdl assembler (which is also used by the Mdl 
compiler) provides this ability. 

7.1. The Assembler 

'Ihc Mdf. assembler provides the Mdi. user with a means of writing RSUBRs directly in machine language. 
The assembler is also used as the object language of the compiler. 1his section is a description of the 
assembler, its use, and some of its pseudo-operations. 


7.1.1. General Organization 

Ihc Mdi assembler is written in Mdl to produce code that runs in the Mdl environment. It takes 

arguments in the following form 

<FILE-ASSEMBLE inout-file:strine 
output- file: string 

quick: boolean> 

'ITic arguments arc an input-file containing Mdi, assembly code (possibly for several RSUBRs), an optional 
output-file in which to put the binary output (by default the same file as input but with second file name 
"NBIN"), and an optional third argument which tells whether to use NBIN format output and which under 
normal circumstances should always be T. There arc four other optional arguments which arc the same as the 
second through fifth arguments of ASSEMBLE. 

<ASSEMBLE body 

locals 

messages 

list 

symbols > 

(All the arguments arc optional with the exception of body) 

body may be a CHANNEL, in which ease all instructions in the file associated with the CHANNEL arc assembled, 
or it may be a structured object in which ease all instructions in the object arc assembled. 

locals specifics the OBLIST to use for local symbol lookup when the body is a CHANNEL. 'Phe default is 
<1 . OBL 1ST > when the assembler is called. 

messages is a CHANNEL to receive error messages, etc. It defaults to .MESSAGE-CHANNEL. 

list is a CHANNEL to receive an assembly listing. If list is not supplied, no listing is generated. If list is a 
non-FALSE non-CHANNEL, and messages is a CHANNEL, then the messages CHANNEL will receive the 
address of each label. If list is a FALSE, then no listing is produced. 'Ihc default is . LINE -CHANNEL 


7.0 



116 


The Ml)l. Programming Hnvironmcnt 


(Initially LINE-CHANNEL is FALSE.) 

symbols indicates if true that a DDT symbol table of all the labels for use with " RDB " (see section 7.2) will be 
generated, llic default is .MAKE-SYM-TABLE (Initially HAKE-SYH-TABLE is FALSE.) 

7.1.2. The Assembler as a Program 

The assembler also exists as program called ASSEM, which encapsulates F I LE -ASSEMBLE. 

7.1.3. Format of Assembler’s Source 

'llic Mm. assembler’s equivalent of a line of code is a FORM. It assembles FORMs into instructions in much 
the same way that a typical assembler treats lines of source code. ATOMS at the top level (i.c. not in FORMs) are 
treated as labels, 'flic FORMs arc assembled based on die TYPE of the GVAL of the first ATOM in die FORM, 
llic GVALs of ATOMS whose PNAMEs arc the PDP-10 instructions arc of TYPE OPCODE (PRIMTYPE WORD; 
the ‘value word’ has the 36 bit value of the instruction. For example, in 
<MOVE A* 1 (B)> 

the value of MOVE (in the OP OBLIST) is 0OPCODE *200000000000*. This FORM is assembled directly 
into an instruction. 

If the GVAL of the first ATOM in a FORM is something applicable (SUBR, FUNCTION, RSUBR etc.) the 
FORM is EVALed and the resulting SPLICE of FORMs is assembled. This is how macros and pseudo-ops are 
implemented. Notice that a pseudo-op or macro may produce no code by returning an empty SPLICE. 

7.1.4. Instruction Assembly 

Having determined that a FORM is going to assemble into an instruction, die assembler basically adds up 
the values of all the items in the FORM. In the ease of items of TYPE OPCODE, a full 36 bit add is performed. 
Items of TYPE ADDRESS refer to labels in the program. Since the code is all location insensitive and will 
move around during garbage collection, references to labels must be indexed by accumulator M, the base 
register. Therefore, label symbols include an M in the led half and must also be added in with a full-word add. 
Items of PRIMTYPE WORD other than OPCODES and ADDRESScs arc ANDBed with *777777* before being 
added, and the carry from right half to left half is suppressed. When ATOMS arc found in FORMs that arc being 
assembled into instructions, special lookup rules arc in cffccL If the ATOM has a global value, that value is 
used. If the ATOM docs not have a global value but has a local value, it is used. If the ATOM hits neither a local 
or global value, it is assumed to be a local symbol for this assembly. In this ease the symbol value is used if it 
has already been defined, otherwise it is added to a list of as yet undefined symbols. 


The Assembler 


7.1 



The MDL Programming Environment 


117 


Objects other titan ATOMS or PRIMTYPE WORDS cause the assembler to take special action. 

- LISTs arc used to indicate swapping lcft^nd right halves. For example 

<MOVE (1)> 

would put the 1 in the index field of the MOVE instruction (similar to MIDAS). 

- A VECTOR indicates a constant. The VECTOR may contain any number of FORMS to be assembled 
at the end of the program. For example: 

<PUSH TP* [<1 (1)>]> 

pushes a constant containing 1 in the right and left halves. 

- A FORM is simply EVALed and the value returned is used. 

7.1.5. Initial Symbols 

lhc OBLIST structure in effect during assembly is 
(op nidi DEFAULT local root) 

The OBLIST op is named OP and contains die FDP 10 opcodes, the Mm. accumulator definitions (in both 
accumulator and address fields), and the pseudo-ops. The OBLIST tttdl is named MUDDLE and contains values 
of many labels in the interpreter. 'Ibis enables programs to do things like < J RS T F I N I S > , the standard way 
to exit from an RSUBR. When an instruction is assembled using a symbol from the MUDDLE OBLIST, a fixup 
is also generated so that, if the symbol gets a different value in a new Mm ., the code can be fixed up when it is 
loaded. Local is the user’s local symbol OBLIST and root is the ROOT OBLIST. 

As stated earlier, every accumulator has two symbols associated with it, one for the address field and one 
for the accumulator field. This is because there is no syntax to specify which field is intended. The address 
symbol is simply the accumulator’s name, and the accumulator symbol is the name with an asterisk (*) 
appended to it; e.g., A versus A*. 

7.1.6. Macro Writing 

Whenever an element or subclcmcnt of an instruction is a FORM and the first element of the FORM has an 
APPLICABLE GVAL, the FORM is evaluated and die result (unless it is a SPLICE) is re-evaluated as if it were 
in place of the FORM. This feature constitutes the assembler’s macro facility. 

For compatibility between ‘top-level’ macros, which generate whole instructions, and macros which 
generate parts of an instruction, top-level macros may wish to return several instructions. To indicate that 
what is returned is several instructions, it is necessary to return an object of type SPLICE (PRIMTYPE LIST). 
The elements of the SPLICE arc treated as individual instructions. An empty SPLICE may be returned from 


7.1 


The Assembler 



118 


'Hie Ml)l. Programming Environment 


a macro which is part of an instruction, and the effect is as if a 0 were returned. 'Phis is the only SPLICE 
which may be returned from a macro which is a part of an instruction. 

7.1.7. Pseudo Operations 

The next part of this document will describe pseudo-ops available in the Mdi. assembler. There is no 
difference between a pseudo-op and macro in the assembler except that the pseudo-operations arc supplied 
by the system. , 

<TITLE name:strine > 

This is about the only required pseudo-op. It must be the first instruction to be assembled. It takes one 
argument, the name of the RSUBR being assembled. If additional TITLES arc found in a file being 
assembled, they arc assumed to both end the previous RSUBR and begin the next. The assembler prints each 
TITLE on the messages CHANNEL as it is encountered. 

<SUB-ENTRY entry: atom decl> 

This pseudo-op is used to define additional RSUBR-ENTRYs for the RSUBR being assembled. The entry 
argument is the name of the RSUBR-ENTRY and the optional decl argument is a DECL for the entry. 
CINTERNAL-ENTRY entry: atom ares.rix > 

is used to create an INTERNAL-ENTRY for a GLUEablc RSUBR. Its arguments arc the name of thr 
INTERNAL-ENTRY and the number of arguments that will have been pushed on the stack for it when it is 
called. See also section 7.1.9 for details on writing GLUEablc RSUBRs. 

<DECLARE ("VALUE" dfd decl decl )> 

is used to supply declarations for the RSUBR named in the TITLE. It must occur before any code-generating 
instructions. DECLARE takesa LIST as its one argument The format ofthe LIST is as described in [3]. The 
string "VALUE " is optional; if supplied it causes the first decl to declare the TYPE of the value of the RSUBR. 
Each additional decl is associated with one argument. Special STRINGS may also appear in the LIST with the 
following meanings: 

"QUOTE" The next argument isQUOTEd (not EVALed). 

"OPTIONAL" 'Phe rest of the arguments arc optional (the RSUBR must supply any defaults for these). 

"CALL " If this appears, it must be directly after the "VALUE " decl. It says there is one argument and it is the 
FORM generating the call (see "CALL" for FUNCTIONS in [31). 

"ARGS" ’Phis must be the last STRING. It says treat the rest of the arguments in the FORM as a LIST and 
pass it as the argument (see "ARGS" for FUNCTIONS in [3J). 

"TUPLE" EVAL the rest of the arguments and pass them. 


The Assembler 


7.1 



The MDI. Programming Knvironment 


119 


<END> 

indicates the end of an RSUBR or group of RSUBRs. Only the text between TITLE and END pseudo-ops will 
be processed by the assembler. This makes it possible to intermix assembler source code and normal Mdl 
source code in the same file (although assembly must be done before compilation in such cases). 

<TYPE-C0DE lvDe:atom > 

allows references to the internal TYPE codes for both system and user defined TYPEs. It takes one argument, 
die M ol TYPE name. For example: 

<M0VSI A* <TYPE-CODE FIX» 
puls the TYPE code for FIX into the left half of accumulator A. 

<TYPE-W0RD t\'i)e:atom any ... > 

generates a reference to a word containing die TYPE code for type in the left half and possibly other junk in 

the right half. The first argument is the TYPE name and the rest of the arguments arc optional but if supplied 

arc added into the right half. If die TYPE is an initial TYPE and no right half is generated, a reference to the 

'SJlype' location in the interpreter is generated. For example, 

<PUSH TP* CTYPE-WORD FIX>> 

<PUSH TP* [0]> 

would push a F I X 0 on the stack. 

<GETYP Qi_ tvne:atom > 

has the same form as a PDP-10 instruction. It gets the TYPE code for type into the right half of its 
accumulator from its address. This is done by generating an appropriate LDB (load byte) instruction. 

<MQUOTE obiect:anv > 

allows die RSUBR to reference garbage collected space. It adds its argument to die RVECTOR (if it isn’t 
already there) and evaluates to an address of the form offset ( R), pointing to the value word for object. 
<PQU0TE obiect:anv > 

is identical to <<MQUOTE object:any> - 1 > i.e. it points to the type-word, not die value-word. This is a more 
consistent way to look at things. 

<IQU0TE object: anv label:atom> 

is like PQUOTE except that this will add a new element to the reference VECTOR each time called. The 
optional label if given defines the ATOM to be a label referring to that element. This is the only way to refer to 
diat element again. 

< PSEUDO are:anv > 

evaluates its argument for its side effects and assembles no code. 


7.1 


The Assembler 



120 


The M1)L Programming Environment 


<sixbit snm > 

makes S I XB I T of the legal characters of siring. 

<SQU0ZE sirine sqbits:word> 

makes SQUOZE of the legal characters of siring and sticks the low-order four bits of the optional sqbits in the 
high-order four bits of the value. See the MIDAS Manual [4] for an explanation of the SQUOZE code. 

<BYTE boundar\':fix bvte-size:fix location > 

Example: <BYTE 1 35 (C) 1> is like <( *014300* ) (C) 1>. 

<ARG arenumifix ) 

is like < ( AB ) <* 2 <- .argnum 1>>>. AR6 should not be used in GLUEable code. 

< STACK svml:atom sym2:alom sym3:atom ... > 

makes syml a symbol for < ( TB ) 0>, sym2 a symbol for <(TB) 2>, sym3 a symbol for <(TB) 4>, etc. 

ST ACK should not be used in GLUEable code. 

<DPUSH sc ares > 

<DPOP ac ans > 

<DMOVE Q£ ares ') 

<DM0VEM Q£ ares > 

arc the double- word PDP-10 instructions. For example, 

<DPUSH ac args> 
expands into 

#SPLICE (<PUSH ac args> <PUSH ac args 1>) 

<uhdef? §wiMaim> 

evaluates to true only if the symbol has previously in the code been used as a symbol, but has not been 
defined. 

<if-needed smMi aim msim siism ... > 

If <UNDEF? symbol > evaluates to true, then all the instructions arc inserted at the current location, otherwise 
they are not 

<*IIISERT file-spec.-strine ) 

takes a file and reads instructions from it and inserts the instructions read at the current place. 

7.1.8. The Type RSUBR 

An RSUBR is a Moi. object of PRIMTYPE VECTOR. The first element of an RSUBR is always of TYPE 
CODE (or PCOOE). CODE is of PRIMTYPE UVECTOR, consisting of words or instructions. The second element 
of an RSUBR is an ATOM which is the RSUBR's name. If the RSUBR has declarations they arc the third 
element The rest of the RSUBR contains Mdl objects which must be referenced by the code 


The Assembler 


7.1 



The MDI. Programming Hnvironment ' 


121 


An RSUBR-ENTRY is a VECTOR of two or three items. The first item is either an RSUBR or an ATOM 
whose GVAL is an RSUBR, the second is an ATOM which is the entry’s name and the third is a DECL for the 
entry. The difference between an RSUBR and an RSUBR-ENTRY is that an RSUBR always starts running at 
tiic beginning of the code when it is called while an RSUBR-ENTRY usually starts running somewhere in the 
middle of the code. 

7.1.9. Writing Gluable RSUBRs 

Certain conventions must be followed when writing hand coded RSUBRs in order to get the most benefit 
from GLUEing. If tlic RSUBR (or RSUBR-ENTRY) has "TUPLE" in its DECL, it is already in the best shape 
possible. In all other eases, the code after the TITLE or SUB-ENTRY pseudo-operation should simply push 
the arguments onto the TP stack and PUSHJ P* to one of the internal entries based on the number of items 
on the stack. After the PUSHJ it should do a <JRST F IN I S>. An internal entry is set up by using the 
INTERNAL-ENTRY pseudo-op which takes two arguments: an atom and a fix. The alum acts as if it were a 
label on the next instruction and may be used as a label. The fix specifics how many items (type-value pairs) 
arc on tiic stack at this internal entry. In the simple ease where there arc no optional arguments, only one 
internal entry exists and its number argument is exactly the required number of arguments. If optional 
arguments exist, some kind of dispatch will have to be done. 

In the rest of the body of the RSUBR, no references to AB or TB (through the ARG or ST ACK pseudo-ops or 
directly) can be made, because after GLUEing their contents may be meaningless. All references to the TP 
stack must be indexed by TP. The usual precautions concerning tiic possible movement of code if an INTGO 
orMCALL is done also apply (i.c. the use of <SUBM M* (P)> at the beginning and <JRST MP0PJ> at the 
end of the code arc essentially mandatory). 

7.2. Debugging Binary Code 

Binary code produced by tiic Mill, assembler or the Mdl compiler may be debugged with DDT, like any 
other binary code. However, an interface between that code and the DDT environment must exist. 'That 
interface is the "RDB" PACKAGE. It is obtained by 
<USE "RDB"> 

'Hie symbol table optionally produced by the assembler can be passed to DDT and at the same time the 
RSUBR frozen (moved out of normal garbage-collected space) by: 


7.1 


The Assembler 



122 


llic MD1. Programming Hnvironmcnt 


<RFREEZE name-of-rsubr:atom > 

Note that name-of-rsubr may also refer to an RSUBR-ENTRY. 

f 

<RBREAK mme-of-rsubr:alom > 

is similar, but in addition causes DDT to put a breakpoint at the first instruction of the RSUBR. 

If there is no symbol table, RFREEZE and RBREAK merely freeze the RSUBR and pass up symbols for the 
RSUBR name and any sub-entries. 

In all cases the symbols passed up arc made up of the legal SQUOZE characters (letters, digits, 1 \$, 1 \%, 
! \ . ) of the name, up to six characters. For example the ATOM F00-*BLECH becomes the symbol FOOBLE. 
<ADR obiccl:anv > 

returns the address of object as a FIX. For example, <ADR rsubr> would return the location of the rsubr in 
core. 

<RUNBREAK name- of- rsubr:atom > 

clears the brcakpoint(s) at the beginning of the RSUBR and of any of its sub-entries. 

7.3. Unassembling Binary Code 

Converting compile i or assembled binary code back into something resembling the original assembler 
source code is an operation that is performed primarily in one situation: tracking down a Mm. compiler bug. 
It is, however, almost invaluable in that situation. The PACKAGE containing the unasscmblcr is "UNASSM". 
The main entry is 

UNASSEMBLE code:rsubr-or-eroup 

outputxhannel-orsiring 

glue?:booleati> 

code is the object being unassembled. It is either an RSUBR (not an RSUBR-ENTRY, note), or an ATOM whose 
LVAL is a group (as created by GROUP -LOAD). 

output is where to put the output; if it is a ST R I NG, then the output is put in a file with that name. If output is 
a CHANNEL, then output is done on that CHANNEL, 'llic file is " code UNASSM” by default 

glue? (by default T) tells whether there arc glue bits for the code loaded. If there arc none, this argument 
should be given as a FALSE. 

The output produced by UNASSEMBLE is like the Mm. compiler’s assembler input, with the addition of 
comments which give code and stack offsets for stack slots referenced. This information is useful in tracing 
exactly what is going on in the code, but it is not always accurate, since the compiler’s stack model is 
sometimes too complex for the unasscmblcr to understand. 


Debugging Binary Code 


7.2 



The MDL Programming Environment 


123 


Mijl compiler bug reports arc expected to contain Mdl source and UNASSEMBLEd compiled code if 
possible. 


7.3 


Unassembling Binary Code 



The MDI. Programming Hnvironment 



Tlic M 1)1. Programming Environment 


125 


8. Informational Aids 

This chapter discusses a few programs, most written in assembly language rather than Mdl, which are 
nonetheless of use to Mdl programmers. Most arc informational aids of one sort or another. They include: 

MUDCOM, a program for comparing versions of a Mdl program. It is used by combat (see section 5.2) to aid 
in the preparation of compiler plan files. It has several useful aliases. 

Mat, the Mdl ‘atsign’ program, produces listings, indexes and cross-reference files for Mdl programs. 0, a 
similar program which is not MDL-spccific, will perform approximately die same tasks. 

Mudinq is an interface to the ITS IPC device and is therefore a means of interacting with any Mdl that has 
the IPC device enabled. It has an alias, STATUS, which is particularly useful for determining the progress 
of compilations. 


8.1 . File Comparison and Checking with MUDCOM 

Mudcom is an assembly language program (not written in Mdl), which nonetheless understands the 
syntax of Mdl programs. It is used for comparing two versions of the same program, and also (under the 
name Mudciik) for checking the syntax of Mdl source files more rapidly than they can be loaded into a 
Mdl. Mudcom is not interactive; all instructions must be passed on the jel line. 


Mudcom understands the following Mdl structures at top level: 


FUNCTIONS 

MACROS 

GVALs 

LVALs 

MANIFEST 

PACKAGE 

ENTRY 

ENDPACKAGE 

MSETG 


<DEFINE F00 > 

<DEFMAC BAR > 

<SETG MUMBLE > 

<SET MUMBLE > 


<MSETG F00 1> is <$ETG F00 1> MANIFEST F00> 


ITic jel for Mudcom in the simplest ease is filename! ,filename2. Mudcom will compare the two files and 
print out information concerning those structures it understands which have been removed, changed, or 
inserted. 


Mudcom has a number of switches which can be set. 'ITicy arc given as / switch , where switch is the name 
of the switch. Currently the following switches arc useful: 

T prints totals at the end of the comparison. 

L prints all FUNCTIONS and GVALs in the file. 


8.0 



126 


nic Ml)l. Programming Hnvironment 


C checks the file given for syntax (only one file name at a time). 

M checks the files for changed MACROS' and MANIFESTS In this mode, Mudcom will make a second pass 
through the first file given in the jel, looking for all occurrences of calls to changed MACROS and 
MANIFESTS. Mudcom will consider FUNCTIONS making such calls as having been ‘changed’ and will tell 
which MACRO or MANIFEST caused the ‘change’. 

'ITic following other jel is understood by MUDCOM: 

(atom ) appearing before the file names in the jel will cause Mudcom to think that those FUNCTIONS 

have been changed and will print them as such. 

" filename " appearing anywhere in the jel causes commands to be read from that file until the end-of-file is 
reached. 

{ filename ... ) is used to specify files to search in calls to MUDI-ND (see below). 

Aliases of Mudcom: 

1. MUDCllK. MUDCHK filename checks a file for Mdi. syntax errors. This is the same as 

MUDCOM /C filename 

2. MUDIST. MUDLST filename lists all FUNCT IONs and GVALs found in the file. This is the same as 

MUOCOM /L filename 

3. Mudfnd. :MUDFND atom . . . {file file } searches files for FUNCT IONs/GVALs called atoms. It 
can be used for finding a FUNCTION in a haystack. This is the same as 

MUDCOM ( atom atom) {file file } 

Since typing this can be tedious, it is easier touscthc"filen ame " convention and have a disk 
file containing the files to be searched (surrounded by (}s). Thus, 

MUDFND FOO BAR BLETCH "MARC;Z0RK FILES" 

will look for the typical FUNCTION names in the files specified in MARC ; ZORK F ILES. 

8.2. The MDL Listing Program MAT 

Mat is a program for producing listings of MDL programs on the Xerox Graphics Printer (XGP) or a 
lincprintcr. (Mat is short for ‘MDL Atsign’, after the general listing program named 8). 

Resides a listing of the program itself, MAT includes a symbol table -- a list of defined objects (arguments to 
DE F 1 NE. SETG, etc.) and optionally a cross-reference listing - a list of every place in the program each ATOM 
is used. MAT can also a produce a record fie, so that the next time MAT is run on the same program, only pages 
that have changed will be printed. 


File Comparison and Checking with M UDCOM 8.1 



Ilic MDL Programming Environment ' 


127 


Mai is invoked with a ye/ line in the following format: 

MAT lrec= out put input- files . . . /switches . . . 

More specifically, it takes any number of input files (separated on the jel line by commas) and produces a 
listing of them in the output file, with options specified by the switches (each preceded by a /, and optionally a 
record file Irec (sec section 8.2.4). 

The output file name defaults on ITS to xuname; input @ or 0XGP depending on whether the X switch is 
used, and on Tencx/TOl^-20 to input . MAT or input. XGP in the connected directory. 

8.2.1. MAT Switches 

flic specific sorts of options available in Mat are controlled by a variety of switches which determine such 
things as whether to produce a cross-reference listing, whether to use the XGP as the output device, and so 
on. The following switches arc implemented: 

/C 

causes a cross-reference listing to be produced. This is a tabic showing each reference to each ATOM (other 
than SUBRs, FSUBRs, and locals) in the input files. 

/D[file-name] 

specifics file-name as the file containing the user’s definitions. Definitions arc discussed in detail below. 

/ F [ text- font , header- font , comment-font'] 

specifics the XGP fonts to use in the output file. They are respectively the font to use for the program itself, 
the font for subtitles and other headers, and the font for Mnt. COMMENTS and top-level STRINGS. 'Hie 
default directory is FONTS and the default second file name is KST. The default font is 20FG. /F also causes 
a /X to be performed. 

/ 1 [ file-name ] 

specifies a file which contains the names of input files. This is in lieu of typing them all in each time Mat is 
run, useful for large subsystems incorporating many files. The input files listed should be separated by 
commas or carriage-returns. 

/N 

causes output of only the symbol tables and cross-reference listing (if specified). No heading or title pages are 
produced. 

/P 

On ITS, VALRETs a : PROCED to DDT and continues. Useful for long Mat runs. 


8.2 


The MDL Listing Program MAT 



128 


llic MDL Programming Hnvironment 


/Q[message'] 

prints message at the bottom of each page. lhc default is a copyright message. 

/R 

creates a record file (this is automatic if 7rec=’ is used). See below for details about record files. 

/S 

outputs each file in a multiple file listing separately. 

/I [name l name2 ] 

specifics names to use on the title page (in lieu of the file names of first inpul file). 

/U 

prints a separate symbol table for each type of defined item in the inpul file(s) (c.g. FUNCTION. GVAL, etc.). 

/X 

declares that output is to be for the XGP. Iliis changes the default output file second name to 0XGP. If /F is 
used, /X is done automatically. 

8.2.2. Subtitles 

Subtitles can be used by including STRINGS in an input file which begin with the word SUBTITLE. The 
remainder of the STRING will be used as part of the header of each output page until another subtitle is 
found. The STRING need not be a COMMENT. Subtitles may have a maximum of79 characters. 

Any file containing subtitles will have a table of contents at the beginning of the listing. 

8.2.3. MAT Definition 

The facility exists in Mat to cause user specified actions to occur at the time a specific ATOM is about to be 
cross-referenced. The most important use of this is for functions which define things which the user would 
like Mat to recognize, for example, a function one of whose side-effects is to SETG one of its arguments. 

When Mat encounters an invocation of the function F00, where F00 has been defined to Mat, it runs 
code generated by the user’s Mat definition for F00. which causes various actions to be performed. 

Mat definitions arc always located in a disk file which is specified by the /D switch. Hach definition must 
be of the form: 

[ name argl arg2 arg3 ...] 

where name is the name of the item which is being defined and the nrgs arc action specifications as described 
below. 


U 


'ITic MDL Listing Program MAT 



The MOL Programming Hnvironment 


129 


The syntax of a Mat definition is somewhat complex. Basically, there arc two types of actions which can 
take place: ‘setting’ an ATOM to be equivalent to a specified type (i.c., FUNCTION, MACRO, etc.) or 

t 

‘cross-referencing’ the ATOM (i.c., making it appear in the cross-reference listing). 

'Fhc actual definition for an ATOM is a string of Mat action specifications, one for each argument in a call 
to that ATOM. For example, defining FOO to be 
[F00 SETG SKIP SETG] 

implies at least three arguments to FOO, the first and third of which should be treated as if they were SETGed. 
Thus, if 

<F00 FROB 1 MUMBLE > 

were encountered in an input file, it would be treated as though 

<SETG FROB any> 

<SETG MUMBLE any> 

had been encountered. 'Fhc symbol table would then point to the line on which the application of FOO 
appeared as the location of the definitions of FROB and MUMBLE. 

'Fhc following tokens arc meaningful action specifications: 

CREF means to cross-reference this ATOM. 

SKIP means to do nothing with this argument (a place holder). 

REST means that the rest of the action specifications may be repeated for the rest of the arguments. 

name (where name is the name of a Mdi. SUBR which causes some action to be routinely performed) means to 
act as though die ATOM had had that SUBR applied to it. For example, SETG will cause Mat to treat the 
item as if a SETG had been performed on it Similarly, MANIFEST will cause Mat to believe it 
MANIFESTed. 

ALSO means to do another thing to this ATOM. Thus, [SETG ALSO MANIFEST] specifics that the argument 
should be treated as though it were both SETGed and MANIFESTed. 

-xy where xy arc two characters, causes a user defined symbol type to be created. In the cross-reference, this 
will appear as xy in front of the name of the ATOM. 

Any of the preceding tokens may have 1 -oblist added. This means that instead of the ATOM being set to 
the specified type, afom\ -oblist will be set Thus, for example, 

REST SETG 1 -FLAGS 

might specify a function which takes a LIST of ATOMS and performs 


12 


The MOL. Fisting Program MAT 



130 


The MDI. Programming Environment 


<SETG < INSERT atom <GET FLAGS 0BLIST» any> 
on each of them. 

f 

[SPEC xy /KJHie] specifics name to be the expansion of jry for purposcs of the symbol table. Name cannot 
have spaces in it 

Since not all items to be recognized within a function call are at top level, there is a facility for telling Mat 
to recognize structures. This is done by inserting the correct bracket (which Mat will encounter) around the 
part of the action specification referring to a structure. For example, a definition for GDECL (which is 
handled internally, however) might be 
REST (REST GDECL) SKIP 

which specifics that the arguments arc alternately a LIST of tilings to GDECL and an argument which is 
unimportant 

A special case of bracketing is when the location of the structure is not known. In this case, bracked 
means 'find the next object that starts with this bracket'. An example later demonstrates this. 

What follows arc some examples from a real definition file. 

[NEWSTRUC NEWTYPE SKIP REST SETG SKIP] 

NEWSTRUC takes an ATOM which becomes the name of a NEWTYPE, the DECL for tiiat TYPE (which is not 
interesting to Ma t) and an arbitrary number of pairs of ATOMs (names of offsets in the structure) and their 
DECLs (again, not interesting). 

[FLAGWORD REST SETG] 

FLAG WORD takes an arbitrary number of ATOMS and SETGs them something. 

[SPEC PG Pure-Gval] 

[SPEC OB Object] 

[SPEC AC Action] 

[SPEC VB Verb] 

[SPEC OS Object-Synonym] 

[SPEC AD Adjective] 

llicsc define the long descriptions for the newly defined symbol types created in the examples. 

[PSETG *PG] 

PSETG takes an ATOM and a value and SETGs the ATOM (also putting it in a LIST of ATOMs to purify). 
[GET-OBJ "CREF"] 

GET-OBJ takes a STRING PNAME of an object and returns the objccL This definition allows * object " to be 
cross-referenced here. Note that C RE F is in quotes because the element being dealt with is a STRING. 


The MDL Listing Program MAT 


U 



The MI)L Programming Environment 


131 


[OBJECT [ " =0B " REST -=0$"] [REST "=AD"]] 

OBJECT creates objects which arc referenced by GET-OBJ. OBJECT first takes a VECTOR of STRINGS, the 
first of which is the true object specifier (OB) and the rest of which are synonyms (OS), The second argument 
is a VECTOR of STRINGS, which arc PNAMEs of adjectives referring to the object (AD). 

[ADD-ACTION "=AC ! -ACTIONS" SKIP REST [[! "=VB ! -WORDS" SKIP]]] 

ADD-ACTION creates ‘verbs’. The name of the verb is the first argument, which is a STRING. ADD-ACTION 
SETGs siring\ -ACTIONS to an item of type ACTION (AC). 'Hie second argument is not interesting. The rest 
of the arguments are VECTORS, somewhere in which is a VECTOR of a STRING and an uninteresting object 
ADD-ACTION SETGs this latter STRING (the PNAME of an ATOM in the WORDS OBLIST) to something of 
type verb (VB). Ibis is about as complicated as a Mat type specification is likely to get 
[1ADD-ACTI0N "=AC ! -ACTIONS ALSO =VB! -WORDS"] 

1ADD-ACTION Likes as its first argument a STRING which is SETGed both in die ACTIONS OBLIST and in 
die WORDS OBLIST, tpan ACT ION (AC) and a verb (VB), respectively. 

8.2.4. MAT Record Files 

Listing Record (or LREC) files, akin to @ LREC files, can be produced in Mat by including file= in the jel 
line. Use of an LREC file has the advantage that future invocations of Mat using it need only output the 
changed pages of the listing. The LREC file produced will be placed in file and contains all relevant jel 
information, so that future calls to Mat for comparison listings need only have file- in the jel line. Additional 
jel may then be appended. There is, however, no way to turn off flags once set up. Therefore, if a 
cross-reference file is to be used only occasionally, leaving the cross-reference (/C) flag off for the initial 
listing and appending it at other times is preferable. 

An alternate way of creating a Listing Record file is to use /R which is equivalent to 
input- file- firsl- file- name LREC® 

in the jel. Obviously, /R is not sufficient for future comparisons. 

8.3. The MDL-IPC Device Interface MUDINQ 

Mudinq is a small program diat formulates, sends, and receives messages to and from Mm .s over die ITS 
1PC (‘Intcr-proccss Communication’) device. The user specifics a target Mm. process by its uname and jname, 
either on the ye/ line or to Mudinq directly. He then inputs the message to be sent to that Mni.. The message 
sent is enclosed in an invisible protective shield (an ERROR handler and so forth) to prevent it from 
interfering in the operation of the target. The message is PARSEd and EVALed by the target, and the result 
put in a file which is printed by Mudinq when it appears. 


8.2 


The M13L Listing Program MAT 



132 


The MDL Programming Hnvironment 


The most common use of this program is to answer the question ‘What could my compilation (or 
whatever) be doing after all this time?’ The answer may be obtained by MuDlNQing a <FR&> or <FRAMES> 
at it 

Inquiring after the state of a compilation is such a common use of Mudinq that there is an alias of it. 
Status, which MuniNQsa <STATUS> (see section 5.1.1) at a compiler process and waits for a response. 

Finally, an alias of Mudinq called Whom lists those Mdi. jobs listening on the IPC device. 

For more details on the operation of the Mot, IPC interface, see [3J. 


The MDL-1PC Device Interface MUDINQ 


8 J 



The MDL Programming Environment 


References 


Edward H. Black. 

Using MDL 's Calico User Interface. 

Technical Report SYS. 11.21, MIT LCS Programming Technology Division, 1976. 


Richard M. Stallman. 

EMACS. 

'Technical Report 519, MIT A1 Laboratory, August, 1979. 


S. W. Galley and Greg Pfister. 

The MDL Programming Language. 

M.I.T. Laboratory for Computer Science, 1979. 


Peter Samson. 

MIDAS. 

Technical Report 90, MIT A1 Laboratory, October, 1965. 


P. David Lcbling, R. V. Baron and Bruce K. Daniels. 

RMODE A Real-time Edit Facility. 

Technical Report SYS.04.07-1, MIT LCS Programming 'Technology Division, October, 1977. 


Table of Contents 



The MDI. Programming Hnvironment 


Table of Contents 



135 


The MDL Programming Environment 


Index 

BK 29 


"XCOMBT TAILOR* 91 

BLOCK 9.40 

"<MDL . SV> " 74 

BOOLEAN 111 

"<MDL>FIXUP.FILE" 73 

BOUND? 49 

"<HDL>SAV. FILE" 73 

BREAKfli 29 

"<MDLLIB>" 73 

BUILD-TEMPLATE 113 

"ADDED FILES* 74 

BYTE 120 

"CLEAN" 109 

C 26 

"CRITIC" 55 

C: 26 

"DEBUGR* 41 

CAN-NOT-BE-DUMPED 15 

"DELETE FIXUPS" 73 

CAREFUL 82,87 

"DELETE SAVS" 73 

CHANNEL 40 

"EDIT" 19 

CLEAN-MONITORS 49 

"FINDATOM" 50 

CLEANUP 109 

"FRMSP" 19 

CLISTF 74 

"GLUE" 103 

COMBAT 79,83,85,90 

"GRLOAD" 39 

COMMENT 15,16 

"L" 69 

COMPILE 79,92,93 

"LUP* 71 

COMP I LE-T UNCTION 93 

"MONITOR" 30,46 

CRITIC 55 

"MUDMAN" 3 

CRITIC-NOTES 55 

"MUDRST" 74 

CU 28 

"MUDSAV; FIXUP FILE" 73 

D 24 

"MUDSAV-.SAV FILE" 73 

DBMAIN 74,76 

"MUDTMP" 73,106 

DEBUG 41 

"PDUMP" 106 

DEBUG-COMPILE 81,85 

"PKG" 10 

DEBUGR 15 

"PP" 15 

DECLARE 118 

"PRELOD" 107 

DEFER-FIND 70 

"PURITY" 108 

DEFINE 41 

"RDB" 116,121 

DELETE 75 

"RECORD" 80 

DL 23 

"SUBRFY" 107 

DMOVE 120 

"TEMHAK" 113 

DMOVEM 120 

"TEMHLP" 113 

DO 27 

"TEMPLATE" 110 

DPOP 120 

"TRACE" 44 

DPUSH 120 

"UNASSM" 122 

DR 23 

"UNLINK" 54 

DROP 10,13 

& 18.21 

DUMP-RSUBRS 114 

&1 18 

DUMP-TEMPLATES 114 

&LIS 18 

E-PKG 20 

• 22 

E-VERBOSE 25 

•INSERT 120 

EDIT 15,19,41 

.NULL 15 

EDIT-TABLE 31 

.OUTCHAN 15 

END 118 

? 22 

ENDBLOCK 9 

?? 22 

ENDPACKAGE 10,13 

ADDRESS 116 

ENTRY 10,12,63 

ADR 122 

ENTRY-FIND 70 

ALREADY-USED-ELSENHERE 12 

, ENV 61 

ARG 120 

EPRIN1 17 

ASSEM 116 

E PRINT 17 

ASSEMBLE 115 

ERRET 38 

ASSIGNED? 49 

EVAL-WHEN 61 

B 23 

EXPERIMENTAL 85 

BA 29 

EXPFLOAD 41.82.87 


Table of Contents 



The MI)L Programming Environment 


EXPSPLICE 41,82,87 
EXTERNAL 13 
F 23 

FBIN 72,105 
FCOMP 80,85 
FEATURE? 61 
FEATURES 61 
FILE- ASSEMBLE 115 
FILE-COMPILE 79 
FILE-TEMPLATE 113 
FIND-FILE 75 
FI NO ATOM 50 
FIXUP 15.72,106 
FLIST 75 
FLOAD 14,107 
FLUSH-CLEANUP 110 
FORM-FAST 44 
FRA 18,37 
FRAP 19 
FRAVAL 19 
FRAMES 18,37 
FRATM 19 
FRLVAL 19,37 
FRM 18,20 
FRTYPE 19 
6 25 

GET-FILE 75 
6ETYP 119 

GLUE 82,87.103.104.107.121 
GO 28 

GROUP-DUMP 39.104.113 
GR0UP-6LUE 104 

GROUP-LOAD 26.39.82.106.107.108 

GROUP- PURIFY 108 

HAIRY- ANALYSIS 83 

HELP 43 

1 25 

I* 26 

I: 25 

IF-NEEDED 120 
16 26 

IN-BREAK 44 
IN-PRINT 45 
INCNAN 59 
INDENT -OIF 43 
INDENT- INC 43 
INDENT-MOD 43 
INITIAL 14.65 
INTERNAL-ENTRY lit. 121 
I QUOTE 119 
IT 27 
K 26 
K: 27 
KB 30 
KC 28 

KEEP-FIXUPS 15.16,41 
KILL -ALL-MONITORS 49. 
KILL-NONITON 49 
KILL-SUBRFY 107 


KILL:PURITY 108 
KT 30 
L 23 

L-ALWAYS-INQUIRE 68 
L-COUNTE 69 
L-COUNTP 69 
. L-FILE 69 
L-FIND 69 
L-LISTE 69 
L-LISTP 69 
L-LISTPE 70 
L-LOAD 69 
L-NO-DEFER 66,68 
L-NO-MAGIC 68 
L-NOISY 68 
L-OBL 70 
L-PATH 70 

L-SEARCH-PATH 64,68,69 

L-SECOND- NAMES 64,65,68 

L-TRANSLATIONS 67 

L-UNUSE 10,13 

L -WHERE 69 

LAST-OUT 42 

LIB-GC 72 

LIBMUD 64 

LINE -CHANNEL 115 

LISTF 74 

LOAD 14 

LOOKAHEAD 16 

LUP-ACT 71 

LUP-AOO-DATUM 72 

LUP-DCT 71 

LUP-DEL 72 

L UP-MOVE 72 

M 27 

MACRO 86 

MACRO-COMPILE 82,87 
MACRO-FLUSH 82.87 
MAGIC-RSUBR 40 
MAKE-SYN-TABLE 116 
MANIFEST 86 
MAX-SPACE 82,87 
MCALL 103 
MONITOR 47 
MONITORS 49 
MONOBJ 48,49 
MOMS PEC 49 
MQUOTE 119 
MUOOLE 117 
MCMVAL 48 
NODE 94 
NPCOMP 79 
0 23 

OBLIST 9.59 
OLDVAL 48 
OP in 
OPCODE 116 
OT 23 

OUT-BREAK 45 


Table of Contents 



'Hie MDL Programming Hnvironment 


OUT -FAST 44 
OUT -PR I HT 45 
OUT-UNIQUE 44 
OUTCHAN 59 
P 25 
PA 29 

PACKAGE 10,11,12.14,63 
PACKAGE-FINO 70 
PACKAGE-MODE 81.86 
PC 29 
PCODE 76 
PCOMP 79,90 
PDUMP 104,106 
PNAME 14 
PPRINF 16 
PPRINT 15 
PQUOTE 119 
PRECOMPILED 81,86 
PRIN1 17 

PRINT-CLEANUP 110 
PSEUDO 119 
PT 25 
PU 25 
PURE? 54 
PURELST 109 
PURIFY 107 
Q 22 
QR 22 

QUICKPRINT 16 
R 23 

RDREAK 122 

READ! -INTERRUPTS 46 

REASONABLE 82,87 

REDEFINE 16 

REDO 81,86 

RENTRY 12 

REPAIR 42 

RETRY 39 

RFREE2E 121 

RM 31 

ROOT 12 

RPACKAGE 12 

RUNBREAK 122 

RVECTOR 107 

RW 30 

S 24 

SAV 72,106 
SAVE 108 
SELF-FAST 44 
SHORT-PRINT 29 
SIXBIT 119 
SL 24 

SOURCE 81,87 
SPEC-FIND 75 
SPECIAL 81,87 
SQUOZE 120,122 
SR 24 
STACK 120 
STATUS 75.80 


SU 27 

SUB-ENTRY 118 
SUBRFY 106,107 
SURV 104 
SW 27 

TEMPLATE 110 
TEMPLATE-DUMP 113 
TEMPNAME 81,86 
TITLE 118 
TRACE 15,44,45 
TRANSLATE 67 
TRANSLATIONS 67 
TYPE -CODE 119 
TYPE -WORD 119 
U 24 
UC 28 
UL 24 
UM 30 

UNASSEMBLE 122 
UNDEF? 120 
UNLINK 54 
UNPURIFY 54 

UNPURIFY- PAGE ! - 1 UNLINK 54 
UNTRACE 45 
UNTRANSLATE 67 
UR 24 

USE 10,12,13.14,63 
USE-DATUM 10,13,14 
USE-DEFER 66 
USE -TOTAL 66 
UT 23 
V 21,25 
VALUE 40 
VERBOSE 45 
VERTICAL 16 
WM 31 

WRITE! -INTERRUPTS 46 

X 27 

tA 42 

tE 42 

tF 22 

tN 42 

tO 42 

tQ 42 

tR 42 

tS 23 

Mat 126 
Mudciik 126 
Mudcx>m 86,125 
Mudpnd 126 
Muimnq 131 
Muuist 126 


Table of Contents